C++ 可变模板无法匹配常量和非常量std::string
我在构建变量模板时遇到了问题,在该模板中,扩展函数正确地匹配非常量和常量C++ 可变模板无法匹配常量和非常量std::string,c++,c++11,variadic-templates,C++,C++11,Variadic Templates,我在构建变量模板时遇到了问题,在该模板中,扩展函数正确地匹配非常量和常量std::string。我有一个通用的匹配函数,它在某些情况下被调用 我已将代码简化为以下示例。不是字符串的东西应该在泛型函数中结束。作为字符串的东西应该在第二个函数结束,该函数额外输出“string” #包括 #包括 模板 无效扩展\u异常(X&ex、T&value) { 这是一个相当棘手的问题,T&&是一个所谓的通用参考,但std::string&&不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法: t
std::string
。我有一个通用的匹配函数,它在某些情况下被调用
我已将代码简化为以下示例。不是字符串的东西应该在泛型函数中结束。作为字符串的东西应该在第二个函数结束,该函数额外输出“string”
#包括
#包括
模板
无效扩展\u异常(X&ex、T&value)
{
这是一个相当棘手的问题,T&&
是一个所谓的通用参考,但std::string&&
不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法:
template<typename X, typename T>
void extend_exception_( X & ex, T&& value, ... )
{
ex << value << std::endl;
}
template<typename X, typename T,
typename = typename std::enable_if<
std::is_same<std::string, typename std::decay<T>::type>::value>::type>
void extend_exception_( X & ex, T && value, int )
{
ex << "STRING: " << value << std::endl;
}
template <typename T> using identity = T;
template<typename X, typename ... R>
void extend_exception( X & ex, R&& ... rest )
{
identity<bool[]>{false,(extend_exception_(ex, std::forward<R>(rest), 0), false)...};
}
int main()
{
extend_exception( std::cout, std::string( "Happy" ) );
std::string var( "var" );
extend_exception( std::cout, var );
extend_exception( std::cout, var, std::string( "Combo" ) );
}
模板
无效扩展\异常\异常(X&ex,T&value,…)
{
这是一个相当棘手的问题,T&&
是一个所谓的通用参考,但std::string&&
不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法:
template<typename X, typename T>
void extend_exception_( X & ex, T&& value, ... )
{
ex << value << std::endl;
}
template<typename X, typename T,
typename = typename std::enable_if<
std::is_same<std::string, typename std::decay<T>::type>::value>::type>
void extend_exception_( X & ex, T && value, int )
{
ex << "STRING: " << value << std::endl;
}
template <typename T> using identity = T;
template<typename X, typename ... R>
void extend_exception( X & ex, R&& ... rest )
{
identity<bool[]>{false,(extend_exception_(ex, std::forward<R>(rest), 0), false)...};
}
int main()
{
extend_exception( std::cout, std::string( "Happy" ) );
std::string var( "var" );
extend_exception( std::cout, var );
extend_exception( std::cout, var, std::string( "Combo" ) );
}
模板
无效扩展\异常\异常(X&ex,T&value,…)
{
ex您不能将非右值绑定到右值引用,因此string&
不起作用,但是const std::string&
适用于var
。但是,var
不是常量,因此到达有效重载的最短路径是将t&&
折叠到std::string&
,然后取第一条路径
您需要找出互斥的类型,或者使用SFINAE编写两个在正确类型的参数上相互排斥的类型。您不能将非右值绑定到右值引用,因此string&&
不起作用,但const std::string&
适用于var
。但是,var
不是常量,所以通往有效重载的最短路径是将T&&
折叠到std::string&
并取第一条
您需要找出互斥的类型,或者使用SFINAE在正确类型的参数上编写两个相互排斥的类型。这是因为您的字符串版本只捕获作为右值传递的字符串。左值将传递给泛型函数。T&&和string&&&,或者更一般的T之间存在巨大差异&&和U&,如果T是一个模板参数,而U不是(意思是,U是某个指定的类型)
要使函数按您所希望的方式工作,您需要做的是添加另一个重载:
template<typename X>
void extend_exception( X & ex, std::string const& value )
{
ex << "STRING: " << value << std::endl;
}
模板
无效扩展_异常(X&ex,标准::字符串常量和值)
{
这是因为您的字符串版本只捕获作为右值传递的字符串。左值将传递给泛型函数。如果T是模板参数而U不是(意味着,U是某个指定类型),则T&&和string&&,或者更一般的T&&和U&&&之间存在巨大差异。请参阅Scott Meyers关于
要使函数按您所希望的方式工作,您需要做的是添加另一个重载:
template<typename X>
void extend_exception( X & ex, std::string const& value )
{
ex << "STRING: " << value << std::endl;
}
模板
无效扩展_异常(X&ex,标准::字符串常量和值)
{
ex我重新审视了这个问题,并提出了一个涉及使用类标记的解决方案。我曾与写过一篇文章。我重新审视了这个问题,并提出了一个涉及使用类标记的解决方案。我曾与写过一篇文章。仅通过值传递似乎有效,尽管我怀疑它是否“正确”@Griwes,是的,按值计算是有效的,但我不想不必要地复制东西。只是按值计算似乎有效,尽管我怀疑它是否“正确”@Griwes,是的,按值工作,但我不想不必要地复制东西。在它的用法上面定义了5行:identity
是标识;)你可能想使用std::decation
而不是std::remove\u reference
,否则对于const std::string
测试失败。a本机使用std::remove_cv
和std::remove_reference
,但在这种情况下,std::decay
的类型较少,并且是等效的。我无法测试这一点,因为在GCC 4.7(您的身份声明)之前不支持模板别名。您能验证我在示例中添加的参数(最后一次使用常量转换扩展_异常的调用)还可以使用此代码吗?是的,要在没有SFINAE的情况下正确使用它,需要为每个专用类型使用三个函数(这里是std::string)。在其用法上方定义了5行:identity
是标识;)您可能希望使用std::decay
而不是std::remove_reference
,否则是相同的
测试因const std::string
而失败。a本机使用std::remove_cv
和std::remove_reference
,但std::decay
在本例中的类型较少且等效。我无法测试这一点,因为直到GCC 4.7(您的标识声明)才支持模板别名。您能否验证我在示例中添加的参数(最后一次使用const_cast调用extend_exception)仍然可以使用此代码?是的,要在没有SFINAE的情况下正确使用它,每个专用类型(这里是std::string)需要三个函数。&
也不能捕获可变引用。您需要添加两个其他重载。&
也不能捕获可变引用。您需要添加两个其他重载。