Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 可变模板模拟;“运行时”;膨胀_C++_Templates_Variadic Templates - Fatal编程技术网

C++ 可变模板模拟;“运行时”;膨胀

C++ 可变模板模拟;“运行时”;膨胀,c++,templates,variadic-templates,C++,Templates,Variadic Templates,我有一个函数,我正在尝试将其转换为使用可变模板。不幸的是,在编译时尝试强类型化函数时,模板扩展会导致问题 以下是旧代码: std::unique_ptr<std::stringstream> Execute(CommandType command, ...) { auto resp = std::make_unique<std::stringstream>(); va_list vl; va_start(vl, command); sw

我有一个函数,我正在尝试将其转换为使用可变模板。不幸的是,在编译时尝试强类型化函数时,模板扩展会导致问题

以下是旧代码:

std::unique_ptr<std::stringstream> Execute(CommandType command, ...) {
    auto resp = std::make_unique<std::stringstream>();

    va_list vl;
    va_start(vl, command);

    switch(command) {
    case CommandType::Post:
        *resp << Post(va_arg(vl, char *), va_arg(vl, char *));
        break;
    case CommandType::Get:
        *resp << Get(va_arg(vl, char *));
        break;
    case CommandType::Delete:
        *resp << Delete(va_arg(vl, char *), va_arg(vl, char *));
        break;
    }
    va_end(vl);
    return resp;
}
理想情况下,我希望能够将其转换为以下内容:

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

    return response;
};

bool Post(std::string command, std::string payload);
std:string Get(std::string command);
bool Delete(std::string command, std::string name);
int OtherFunc(std::string command, bool enabled, MyClass name);
模板
std::unique_ptr Execute(CommandType命令、Params…参数){
自动响应=标准::使_唯一();
if(command==CommandType::Get)

响应您可以添加虚拟函数,例如:

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Post (Ts&&...) {return 0;}

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Delete (Ts&&...) {return 0;}

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 3, int>::type
OtherFunc (Ts&&...) {return 0;}

(请注意,我更改了
OtherFunc
,以在没有额外内容的情况下生成错误)。

非常感谢@Jarod42提供了出色的解决方案。我在这里做了一些调整,以在编译过程中警告用户(通过pragma消息)当模板使用不正确时。它不是完美的,但至少它给出了一些执行错误的指示。在VS2013中,您可以双击警告消息,它会将您带到错误行。不幸的是,它是在定义的地方,而不是在使用的地方,但至少它是某种东西,而不是完全没有警告

下面是一个活生生的例子:

注意:请注意下面的代码……WIN32版本中的pragma消息在VS2013中工作,但我不确定GCC是否正确。它可以编译,但我无法在Ideone.com上看到警告消息。因此,如果我没有正确获取GCC的pragma,可能需要进行一些调整

再次感谢@Jarod42

#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
};

#define Stringify( T ) #T
#define MakeString( M, L ) M(L)
#define $Line MakeString( Stringify, __LINE__ )
#ifdef WIN32
#define TemplateErrMsg __FILE__ "(" $Line ") : Invalid template used:" __FUNCTION__
#define INVALID_TEMPLATE { __pragma( message( TemplateErrMsg ) ); assert( false && TemplateErrMsg );  return 0; } 
#else
#define TemplateErrMsg __FILE__ "(" $Line ") : Invalid template used:" MakeString( Stringify, __FUNCTION__ )
#define DO_PRAGMA(x) _Pragma ( #x )
#define INVALID_TEMPLATE {DO_PRAGMA(message(TemplateErrMsg)); assert( false && TemplateErrMsg );  return 
#endif

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 1, int>::type
Get (Ts&&...) INVALID_TEMPLATE

template<typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, int>::type
Get (T&&...) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Post (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Delete (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
OtherFunc (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

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 , 123, "test", MyClass{});
}
#包括
#包括
#包括
#包括
#包括
类MyClass{};
boolpost(std::string/*command*/,std::string/*payload*/){std::cout
typename std::enable_if::value
||!std::是否可转换::值,
int>::类型
Post(T1&,T2&&)模板无效
模板
typename std::enable_if::type
删除(Ts&…)无效的\u模板
模板
typename std::enable_if::value
||!std::是否可转换::值,
int>::类型
删除(T1&&,T2&&)无效的\u模板
模板
typename std::enable_if::type
OtherFunc(Ts&…)无效的\u模板
模板
typename std::enable_if::value
||!std::是否可转换::值,
int>::类型
OtherFunc(T1&&,T2&&)模板无效
模板
std::unique\u ptr
执行(CommandType命令、Ts&&…参数){
自动响应=标准::使_唯一();
if(command==CommandType::Get)

*响应非常有趣!我需要理解你写的东西。使用sizeof查看传递了多少个参数,但是如果函数具有相同数量的参数,那么它将失败。这就是你使用std::Is_convertable所指的吗?但是如何确定在第n个参数上Is_可转换?@user3072517:刚刚添加了代码来修复您的命令函数之间可能不兼容的原型。我向o’template绝地大师致敬!太棒了!绝对太棒了。我根据您的输入稍微调整了它,现在它在未正确使用时会显示编译器消息。老鼠!pragma警告是一个不错的主意,但一旦我开始添加乐趣实际上,警告是生成的,尽管它实际上没有被使用。啊……这是一个很好的想法。顺便说一句,旧代码有未定义的行为。您对
va_arg
的调用不能保证以任何特定的顺序发生——函数参数可以按任何顺序进行计算。我见过编译器根据或各种异想天开的原因,例如更改优化设置后。
template<typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, int>::type
Get (T&&...) {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&&) {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&&) {return 0;}
#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
};

#define Stringify( T ) #T
#define MakeString( M, L ) M(L)
#define $Line MakeString( Stringify, __LINE__ )
#ifdef WIN32
#define TemplateErrMsg __FILE__ "(" $Line ") : Invalid template used:" __FUNCTION__
#define INVALID_TEMPLATE { __pragma( message( TemplateErrMsg ) ); assert( false && TemplateErrMsg );  return 0; } 
#else
#define TemplateErrMsg __FILE__ "(" $Line ") : Invalid template used:" MakeString( Stringify, __FUNCTION__ )
#define DO_PRAGMA(x) _Pragma ( #x )
#define INVALID_TEMPLATE {DO_PRAGMA(message(TemplateErrMsg)); assert( false && TemplateErrMsg );  return 
#endif

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 1, int>::type
Get (Ts&&...) INVALID_TEMPLATE

template<typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, int>::type
Get (T&&...) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Post (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
Delete (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

template<typename ... Ts>
typename std::enable_if<sizeof...(Ts) != 2, int>::type
OtherFunc (Ts&&...) INVALID_TEMPLATE

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&&) INVALID_TEMPLATE

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 , 123, "test", MyClass{});
}