Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++_Templates_C++17_Ctad - Fatal编程技术网

C++ 模板相关参数的类模板参数推断

C++ 模板相关参数的类模板参数推断,c++,templates,c++17,ctad,C++,Templates,C++17,Ctad,让我们从类number的简单add方法开始: class number { int num; public: number(int num = 0): num(num) {} operator int() const { return num; } }; number add(number t1, number t2) { return t1 + t2; } int main() { auto result1 = add(1, 2); // auto-

让我们从类
number
的简单add方法开始:

class number {
    int num;
public:
    number(int num = 0): num(num) {}
    operator int() const { return num; }
};

number add(number t1, number t2) {
    return t1 + t2;
}

int main() {
    auto result1 = add(1, 2); // auto-casting, works fine
}
现在我们要将
number
转换为模板类:

template<class T>
class number {
    T num;
public:
    number(T num = 0): num(num) {}
    operator T() const { return num; }
};

template<class T>
number<T> add(number<T> t1, number<T> t2) {
    return t1 + t2;
}
请注意,如果
add
是一个friend函数,根据以下情况,使用
编号作为参数之一调用该函数将有效:

模板
班号{
T数;
公众:
数字(T num=0):num(num){
运算符T()常量{return num;}
朋友号添加(t1号,t2号){
返回t1+t2;
}
};
int main(){
数字a=3;//工作,使用CTAD
auto result1=add(a,2);//基于ADL工作
//auto result2=add(1,2);//仍然不起作用,此处没有ADL:(
}
如何允许模板类的行为与非模板类类似,在调用add时自动强制转换?


编辑:
这个问题是根据发布的评论编辑的。应该强调的是,对于像
add
这样的通用函数,拥有这样一个自动转换可能是一个错误的想法,但是假设这个方法非常具体,比如
doSomethingWithNumbers
,我认为答案很简单。在第一种情况下,使用免费函数在模板上,首先起作用的是重载解析和函数模板参数推断。因为编译器无法从作为参数传递的
int
中检测
T
(:
候选模板被忽略:无法将'number'与'int'匹配
),重载解析失败,程序格式错误

当函数被定义为
friend
时,它是一个非模板函数。编译器在实例化类时创建了它(对于
number
;在
main
中的第一行)。现在,当它找到它时(使用ADL),参数类型已经设置好了(两者都是
number
,因为它来自
number
实例化),剩下的是决定如何将传递的参数从
int
转换为
number
,其中使用隐式转换(通过匹配的c-tor)。这里也没有CTAD

<> > Scott Meyers在有效C++(第三版)中讨论了一个类似(但不完全相同)的情况,第46项:在需要类型转换时定义模板内的非成员函数。 编辑: 因此,要回答这个问题,函数模板参数推导和参数的隐式类型转换不能混合。选择一个。(这是Meyers在提到的项目中解释的。)

在第行中,我们可以实现所需的行为,尽管它不是自动转换:

// the additional `requires` on number is not mandatory for the example
// but it is reasonable that number would be restricted
template<class T> requires std::integral<T> || std::floating_point<T>
class number {
    T num;
public:
    number(T num = 0): num(num) {}
    operator T() const { return num; }
};

template<typename T>
concept Number = requires(T t) {
    number(std::move(t)); // anything that a number can be created from
                          // that includes number itself
};

auto add(Number auto t1, Number auto t2) {
    return number{std::move(t1)} + number{std::move(t2)};
}

int main() {
    number a = 3;
    auto result1 = add(1, 2);
    auto result2 = add(a, 2);
    auto result3 = add<double>(1, 2);
}
//对于该示例,数字上的附加'requires'不是必需的
//但限制这一数字是合理的
模板需要std::integral | | std::floating_点
班号{
T数;
公众:
数字(T num=0):num(num){
运算符T()常量{return num;}
};
模板
概念编号=要求(T){
number(std::move(t));//可以创建数字的任何内容
//这包括数字本身
};
自动添加(编号自动t1,编号自动t2){
返回编号{std::move(t1)}+编号{std::move(t2)};
}
int main(){
数字a=3;
自动结果1=添加(1,2);
自动结果2=添加(a,2);
自动结果3=添加(1,2);
}

代码:

不清楚这里的问题是什么。为什么要添加(1.0,2.0)
调用一个与
1.0
2.0
的类型完全没有类型关系的函数?为什么编译器会考虑将
number
添加
函数作为一种可能性,特别是如果它在其他名称空间中?而且,这与CTAD有什么关系,因为这段代码中没有任何内容使用CTAD。否,
add
的定义不起作用。在模板定义中,不带模板参数的模板名称与模板当前实例化的名称加倍。
add(编号{1},编号{2})
工作正常,它使用CTAD@bolov是的,确实如此,但问题是如何避免显式创建所需类型的需要,即实现与非模板
number
类相同的行为。Amir,我个人建议不要隐式,但既然您似乎希望隐式,我建议您遵循Grea的思路t参考Meyers。旧但仍然相关。据我所知,从C++20开始,无法按照问题中的要求实现模板依赖类型参数的自动转换。出现了一种变通方法,但它只是一种变通方法。“旧但仍然相关”应该是Scott Meyers所有旧书的座右铭:)几乎没有什么改变了那里讨论的话题
template<class T>
class number {
    T num;
public:
    number(T num = 0): num(num) {}
    operator T() const { return num; }
    friend number add(number t1, number t2) {
        return t1 + t2;
    }
};

int main() {
    number a = 3; // works, using CTAD
    auto result1 = add(a, 2); // works, based on ADL
    // auto result2 = add(1, 2); // still doesn't work, no ADL here :(
}
// the additional `requires` on number is not mandatory for the example
// but it is reasonable that number would be restricted
template<class T> requires std::integral<T> || std::floating_point<T>
class number {
    T num;
public:
    number(T num = 0): num(num) {}
    operator T() const { return num; }
};

template<typename T>
concept Number = requires(T t) {
    number(std::move(t)); // anything that a number can be created from
                          // that includes number itself
};

auto add(Number auto t1, Number auto t2) {
    return number{std::move(t1)} + number{std::move(t2)};
}

int main() {
    number a = 3;
    auto result1 = add(1, 2);
    auto result2 = add(a, 2);
    auto result3 = add<double>(1, 2);
}