Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.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++_String_Templates_Variadic Templates - Fatal编程技术网

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”))

第一种情况包含instantion
adder(“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) + ... );
}