C++ 以下变量模板行为是否不一致?
我尝试下面的例子来理解可变模板,发现行为有些不一致C++ 以下变量模板行为是否不一致?,c++,string,templates,variadic-templates,C++,String,Templates,Variadic Templates,我尝试下面的例子来理解可变模板,发现行为有些不一致 #include <iostream> #include <string> using namespace std; template<typename T> T adder(T v) { return v; } template<typename T, typename... Args> T adder(T first, Args... args) { return fi
#include <iostream>
#include <string>
using namespace std;
template<typename T>
T adder(T v) {
return v;
}
template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}
int main()
{
long sum = adder(1, 2, 3, 8, 7); //Works
cout << sum << endl;
string s1 = "xx", s2 = "aa", s3 = "bb", s4 = "yy";
string ssum = adder(s1, s2, s3, s4); //Works
cout << ssum << endl;
string ssum2 = s1 + s2 + "3" + "4"; //Works as operator '+' is defined in string class for const char*
cout << ssum2 << endl;
string ssum3 = adder(s1, s2, "3", "4"); //Does not work. Expected as binary 'operator+' is not defined for string and const char*
cout << ssum3 << endl;
string ssum4 = adder("3", "4"); //Does not work. Expected as binary 'operator+' is not defined for const char* and const char*
cout << ssum4 << endl;
string ssum5 = adder(s1, s2, "3"); //Works!!!
cout << ssum5 << endl;
}
#包括
#包括
使用名称空间std;
模板
T加法器(tv){
返回v;
}
模板
T加法器(T优先,Args…Args){
返回第一个+加法器(args…);
}
int main()
{
长和=加法器(1,2,3,8,7);//有效
库特
发生这种情况是因为ssum5
的最后一个参数在最后一次迭代时被转换为string
不,它之所以有效是因为重载了std::string
和原始字符串(const char*
)。给定的s2
是std::string
,那么s2+“3”
和“3”+s2
都可以正常工作。所以ssum5
之所以有效,是因为在最后一次递归时它将被解释为s2+“3”
,这很好
问题是您不能将两个连续的原始字符串传递给加法器。对于ssum3
和ssum4
,您传递的是“3”
和“4”
,最后它们将被解释为“3”+“4”
,这显然不起作用。ssum3是加法器(s1,加法器(s2,加法器(“3”,加法器(“4”))
ssum5是加法器(s1,加法器(s2,加法器(“3”))
第一种情况包含instantionadder(“3”,adder(“4”)
,它最终扩展为“3”+“4”
,显然不起作用
第二种情况从未尝试将两个const char*
s添加在一起,因此这很好。您可以使用std::common\u type
修复它
正如其他人所指出的,这与递归的顺序有关
adder(s1, s2, "3")
同:
s1 + adder(s2, "3")
因为这与(对std::strings
求和,也对std::string
加上const char*
,这是合法的)是一样的:
另一方面
adder(s1, s2, "3", "4");
显然无法工作,因为它与相同(最终添加两个const char*
,这是非法的):
为了克服这个问题,您应该使用std::common_type
,它将执行公共类型中的所有添加(在本例中为std::string
):
模板
T加法器(常数T&v){
返回v;
}
模板
T加法器(常数T&first,常数Args&…Args){
返回第一个+加法器(args…);
}
另一种选择是使用C++17折叠表达式(如果您有C++17):
模板
typename std::common_type::type
加法器2(常量参数和…参数)
{
使用type=typename std::common\u type::type;
返回(类型(args)+…);
}
缺点是它会导致字符串等类型的复制构造函数,并且需要C++17。通过使用帮助函数,可以消除额外的构造(包括公共基类):
template <typename Target, typename Source>
typename std::enable_if< ! std::is_base_of<Target, Source>::value,
Target>::type
toType(const Source & source)
{
return source;
}
template <typename Target, typename Source>
typename std::enable_if<std::is_base_of<Target, Source>::value,
const Target&>::type
toType(const Source & source)
{
return source;
}
template <typename ... Args>
typename std::common_type<Args...>::type
addder3(const Args & ... args)
{
using type = typename std::common_type<Args...>::type;
return (toType<type>(args) + ... );
}
模板
typename std::enable_如果<!std::是::value的_base_,
目标>::类型
toType(常量源和源)
{
返回源;
}
模板
typename std::enable_if::type
toType(常量源和源)
{
返回源;
}
模板
typename std::common_type::type
addder3(常量参数和…参数)
{
使用type=typename std::common\u type::type;
返回(toType(args)+…);
}
提示:a+b+c与(a+b)+c相同,通常不同于a+(b+c)。您的评论中的错误是错误的,问题是常量字符*
和常量字符*
没有运算符+
。字符串+常量字符*
有运算符+
,否则只有第一个运算符有效
s1 + (s2 + ("3" + ("4")))
template<typename T>
T adder(const T & v) {
return v;
}
template<typename T, typename... Args>
T adder(const T & first, const Args &... args) {
return first + adder<typename std::common_type<T, Args...>::type>(args...);
}
template <typename ... Args>
typename std::common_type<Args...>::type
adder2(const Args & ... args)
{
using type = typename std::common_type<Args...>::type;
return (type(args) + ... );
}
template <typename Target, typename Source>
typename std::enable_if< ! std::is_base_of<Target, Source>::value,
Target>::type
toType(const Source & source)
{
return source;
}
template <typename Target, typename Source>
typename std::enable_if<std::is_base_of<Target, Source>::value,
const Target&>::type
toType(const Source & source)
{
return source;
}
template <typename ... Args>
typename std::common_type<Args...>::type
addder3(const Args & ... args)
{
using type = typename std::common_type<Args...>::type;
return (toType<type>(args) + ... );
}