gpt4 book ai didi

c++ - 为什么重载解决方案偏爱不受约束的模板功能而不是更具体的功能?

转载 作者:IT老高 更新时间:2023-10-28 22:39:05 25 4
gpt4 key购买 nike

我有这个带有乘法的最小表达式模板库,即

template <typename T, typename U>
struct mul {
const T &v1;
const U &v2;
};

template <typename T, typename U>
mul<T, U> operator*(const T &one, const U &two) {
std::cout << " called: mul<T, U> operator*(const T &one, const T &two)\n";
return mul<T, U>{one, two};
}

并转置,即

template <typename T>
struct transpose {
const T &t;
};

template <typename T>
transpose<T> tran(const T &one) {
return transpose<T>{one};
}

我会介绍一些类型AB , 后者是前者的子类:

template <typename T>
struct A {
T elem;
};

template <typename T>
struct B : A<T> {
B(T val) : A<T>{val} {}
};

然后,我可以如下调用我的表达式模板库(打印到 std::cout 的重载):

template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const mul<T, U> &m) {
os << " unconstrained template \n";
}

int main(int argc, char const *argv[]) {
B<double> a{2};
B<double> b{3};
std::cout << tran(a) * b << "\n";
return 0;
}

这给了我输出:

called: mul<T, U> operator*(const T &one, const T &two)
unconstrained template

到目前为止一切顺利。现在假设我想要对“A<T> 类型变量的转置”进行专门的处理。乘以 A<T> 类型的变量对于某些类型T ',就像我在 main 中所做的那样.为此,我将介绍

template <typename T>
T operator*(const transpose<A<T>> &one, const A<T> &two) {
std::cout << " called: T operator*(const A<T> &one, const A<T> &two)\n";
return one.t.elem * two.elem;
}

我运行相同的 main功能如上,我仍然得到与上面相同的输出(unconstrained template)。这是意料之中的,因为 transpose<B<double>>transpose<A<double>> 相比是完全不同的类型,因此重载解析选择了 operator* 的无约束模板版本.

(当然,如果我将 main 中的变量定义更改为 A 而不是 B ,ADL 将调用专用函数,输出为 called: T operator*(const A<T> &one, const A<T> &two)6 )。

我最近了解了 SFINAE,因此我预计对更具体的乘法运算符的以下更改会导致选择专用函数的重载结果:

template <typename T, typename V>
std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const transpose<V> &one,
const V &two) {
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)\n";
return one.t.elem * two.elem;
}

即使使用 SFINAE 的 operator*我仍然得到 unconstrained template版本。怎么来的?我应该做哪些改变来调用更专业的模板函数?

最佳答案

问题在于,在 SFINAE 过载中,T用于非演绎的上下文中。您实际上是在询问编译器:“如果存在 T 则启用此功能,这样 A<T>V 的基类。”存在量化是一个很好的指标,表明你所要求的不能是 SFINAEd。

如果您禁用不受约束的模板,您可以自己看到这一点,就像我所做的 here .这会强制编译器说明为什么其他函数 Not Acceptable 。

你可以通过 T 来解决这个问题可通过您的 A (因此 B )类,像这样:

template <typename T>
struct A {
using Type = T;
T elem;
};


template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two) {
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)\n";
return one.t.elem * two.elem;
}

[Live example]

关于c++ - 为什么重载解决方案偏爱不受约束的模板功能而不是更具体的功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56360583/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com