[英]Variadic template trouble matching const and non-const std::string
我在构建可变参数模板时遇到了麻烦,其中扩展功能正确地匹配了非const和const std::string
。 我有一个通用的匹配函数,在某些情况下会被调用。
我将代码简化为以下示例。 不是字符串的东西应该以通用函数结束。 作为字符串的事物应该结束于第二个函数,该函数另外输出“ STRING”。
#include <iostream>
#include <string>
template<typename X, typename T>
void extend_exception( X & ex, T&& value )
{
ex << value << std::endl;
}
template<typename X>
void extend_exception( X & ex, std::string && value )
{
ex << "STRING: " << value << std::endl;
}
template<typename X, typename TF, typename ... TR>
void extend_exception( X & ex, TF&& f, TR&& ... rest )
{
extend_exception( ex, std::forward<TF>(f) );
extend_exception( ex, std::forward<TR>(rest)... );
}
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" ), const_cast<std::string const&>(var));
return 0;
}
在以上版本中,两个var
使用不会传递给字符串函数。 我尝试了其他各种方法来指定参数,但似乎没有办法: std::string && value
, std::string const & value
, std::string const && value
。 我也确实尝试过std::string & value
,然后非常量字符串匹配,而不是const字符串。 通过具有两个不同的功能,这至少为我提供了一种解决方法,但是我怀疑我不需要这样做。
如何在此处编写一个将为const,non-const和临时字符串对象调用的函数?
我正在使用g ++ 4.6.3
这非常棘手, 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" ) );
}
您不能将非右值绑定到右值引用,因此string&&
不起作用,但const std::string&
可用于var
。 但是, var
不是const,因此实现重载的最短路径是将T&&
折叠为std::string&
并采用第一个。
您需要找出相互排斥的类型,或使用SFINAE编写两个在正确的参数类型上互斥的类型。
这是因为您的字符串版本仅捕获作为右值传递的字符串。 左值将传递给泛型函数。 如果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;
}
我重新讨论了这个问题,并提出了一个涉及使用类标记的解决方案。 我写了一篇完整的解决方案/讨论文章 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.