#include <cassert>
#include <memory>
#include <sstream>
#include <string>
#include <iostream>

class MyClass {};

bool Post(std::string /*command*/, std::string /*payload*/) { std::cout << "Post\n"; return false;}
std::string Get(std::string /*command*/) { std::cout << "Get\n"; return ""; }
bool Delete(std::string /*command*/, std::string /*name*/) { std::cout << "Delete\n"; return false;}
int OtherFunc(std::string /*command*/, const MyClass& /*name*/) { std::cout << "OtherFunc\n"; return 0;}

enum class CommandType
{
    Get, Post, Delete, OtherFunc
};

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 1, int>::type
Get (Ts&&...) { assert(false && "should not be called"); return 0; }

template<typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, int>::type
Get (T&&...) { assert(false && "should not be called"); return 0; }

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Post (Ts&&...) { assert(false && "should not be called"); return 0; }

template<typename T1, typename T2>
typename std::enable_if<!std::is_convertible<T1, std::string>::value
    || !std::is_convertible<T2, std::string>::value,
    int>::type
Post (T1&&, T2&&) { assert(false && "should not be called"); return 0; }

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Delete (Ts&&...) { assert(false && "should not be called"); return 0; }

template<typename T1, typename T2>
typename std::enable_if<!std::is_convertible<T1, std::string>::value
    || !std::is_convertible<T2, std::string>::value,
    int>::type
Delete (T1&&, T2&&) { assert(false && "should not be called"); return 0; }

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
OtherFunc (Ts&&...) { assert(false && "should not be called"); return 0; }

template<typename T1, typename T2>
typename std::enable_if<!std::is_convertible<T1, std::string>::value
    || !std::is_convertible<T2, const MyClass&>::value,
    int>::type
OtherFunc (T1&&, T2&&) { assert(false && "should not be called"); return 0; }

template<typename... Ts>
std::unique_ptr<std::stringstream>
Execute(CommandType command, Ts&&... parameters) {
    auto response = std::make_unique<std::stringstream>();
    if(command == CommandType::Get)
        *response << Get(std::forward<Ts>(parameters)...);
    else if(command == CommandType::Post)
        *response << Post(std::forward<Ts>(parameters)...);
    else if(command == CommandType::Delete)
        *response << Delete(std::forward<Ts>(parameters)...);
    else if(command == CommandType::OtherFunc)
        *response << OtherFunc(std::forward<Ts>(parameters)...);

    return response;
}


int main(){
    Execute(CommandType::Get, "hello");
    Execute(CommandType::Post, "hello", "world");
    Execute(CommandType::Delete, "hello", "world");
    Execute(CommandType::OtherFunc, "hello", MyClass{});
}
