#include <iostream>
#include <string>
#include <cstdlib>
#define P(x) std::cout<<x<<std::endl

struct Scalar { std::string data = "scalar"; };
struct Array  { std::string data = "array";  };


template<typename ReturnT = void>
ReturnT test() {}

template<>
void test() { P("param: void, return: void"); }

template<> 
Scalar test() { P("param: void, return: scalar"); return Scalar(); }

template<> 
Array test()  { P("param: void, return: array");  return Array(); }


template<typename ReturnT = void, typename ParamT>
ReturnT test(ParamT x) {}

template<>
void test(Scalar x)   { P("param: scalar, return: void"); }

template<>
void test(Array x)    { P("param: array, return: void"); }

template<> 
Scalar test(Scalar x) { P("param: scalar, return: scalar");  return Scalar(); }

template<> 
Array test(Array x)   { P("param: array, return: array");    return Array(); }


int main()
{
   test();
   Scalar a = test<Scalar>();
   Array  b = test<Array>();
   Scalar c = test<Scalar, Scalar>(Scalar());
   Array  d = test<Array, Array>(Array());
   test<void, Scalar>(Scalar());
   test<void, Array>(Array());
}



