我在构造可变参数模板时遇到问题,其中扩展函数正确匹配非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,非const和临时字符串对象?
我正在使用g ++ 4.6.3
答案 0 :(得分:4)
这非常棘手,T&&
是所谓的通用引用,但std::string&&
不是(不涉及类型推导)。有关详细说明,请参阅here。这是一个修复:
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" ) );
}
答案 1 :(得分:2)
您无法将非右值绑定到右值引用,因此string&&
不起作用,但const std::string&
适用于var
。但是,var
不是常量,因此有效的重载的最短路径是将T&&
折叠到std::string&
并获取第一个。
你需要弄清楚相互排斥的类型,或者使用SFINAE来编写两个在正确类型的参数上相互排斥的类型。
答案 2 :(得分:2)
这是因为你的字符串版本只捕获作为rvalues传递的字符串。左值将传递给泛型函数。 T&amp;&amp; amp;和T&amp;和字符串&amp;&amp;和更普遍的T&amp;&amp;和U&amp;&amp;,如果T是模板参数而U不是(意思是,U是某些指定的类型)。请参阅Scott Meyers关于universal references
的说明为了使函数正常工作,您需要做的是添加另一个重载:
template<typename X>
void extend_exception( X & ex, std::string const& value )
{
ex << "STRING: " << value << std::endl;
}
答案 3 :(得分:0)
我重新审视了这个问题并提出了一个涉及使用类标记的解决方案。我写了一篇文章full solution/discussion。