具有自动类型退货扣除的模板

时间:2018-12-17 09:56:06

标签: c++ templates c++17

我已经创建了模板化结构,并正在尝试重载二进制运算符。由于某种原因,即使该类型正确地插入了两者之间,该函数也不会返回正确的数据类型。

template<typename T>
struct Number{
    const T value;
    Number(T a) : value(a) {}

    template<typename U>
    auto operator*(Number<U> other){
        auto new_value = value*other.value;
        std::cout << typeid(new_value).name() << std::endl;
        return Number(new_value);
    }
};

现在,如果我使用main中调用的以下代码执行此操作。它返回第一个类型的Number,而不是较高类型的Number。

auto b =  Number<int>(6) * Number<double>(2.3); // this should be an int*double=double
std::cout << b.value << typeid(b.value).name() << std::endl;
auto c = Number<double>(2.3) * Number<int>(6);
std::cout << c.value << typeid(c.value).name() << std::endl;

输出如下: d 13i d 13.8d

据我了解,当函数返回新的Number(new_value)时,将调用不正确的构造函数。我不了解这种情况的发生方式和原因,因为new_value属于“正确类型”。

3 个答案:

答案 0 :(得分:9)

在模板范围内,模板名称将代表所注入的类名,而不是模板。因此不会有CTAD,and that's by design

使用return Number<decltype(new_value)>(new_value);是简单的解决方法。

答案 1 :(得分:1)

您将返回第一种而不是第二种:

template<typename U>
auto operator*(Number<U> other){
    auto new_value = value*other.value;
    std::cout << typeid(new_value).name() << std::endl;
    return Number(new_value);
}

即使new_value是双精度数,您也将其存储在Number<T>中。

尝试:

template<typename U>
auto operator*(Number<U> other){
    auto new_value = value*other.value;
    std::cout << typeid(new_value).name() << std::endl;
    return Number<decltype(new_value)>(new_value);
}

答案 2 :(得分:0)

StoryTeller指出,在类模板定义中,类的名称是指特定的类实例(称为 injected-class-name ),而不是名称模板。

但是,如果您希望类模板自变量的推论仍然适用,则可以限定名称:

return ::Number(new_value);

::Number是指类模板Number,而不是特定类型Number<T>。但这对于其他阅读您的代码的人来说可能太神奇了,并且简单地使用Number<decltype(new_value)>(new_value)会有很多好处。