C++模板选择 - 不寻常的情况
C++ template selection - unusual case
>我有以下定义
template <typename T1, typename T2> class ArithmeticType {
public:
T1 x1;
T2 x2;
typedef typeof(x1+x2) Type;
};
template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const std::complex<D2>& x2) {
D1 x1r = real(x1);
D1 x1i = imag(x1);
D2 x2r = real(x2);
D2 x2i = imag(x2);
return std::complex<typename ArithmeticType<D1,D2>::Type>(x1r+x2r, x1i+x2i);
}
然后我按如下方式使用此类
std::complex<double> x;
std::cout << typeid(x).name() << std::endl;
ArithmeticType<std::complex<double>,std::complex<float>>::Type y;
std::cout << typeid(y).name() << std::endl;
产生输出
St7complexIdE
St7complexIdE
这对我来说很有意义:y
属于std::complex<double>
型
现在,通过添加复杂和浮动类型的缩进,我添加了operator+
模板的专用化,以便代码成为
template <typename T1, typename T2> class ArithmeticType {
public:
T1 x1;
T2 x2;
typedef typeof(x1+x2) Type;
};
template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const std::complex<D2>& x2) {
D1 x1r = real(x1);
D1 x1i = imag(x1);
D2 x2r = real(x2);
D2 x2i = imag(x2);
return std::complex<typename ArithmeticType<D1,D2>::Type>(x1r+x2r, x1i+x2i);
}
template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const D2 x2) {
D1 x1r = real(x1);
D1 x1i = imag(x1);
return std::complex<typename ArithmeticType<D1,D2>::Type>(x1r+x2, x1i+x2);
}
我运行与以前相同的代码,但现在出现编译错误,因为编译器尝试使用第二个专用化而不是第一个专用化。 这对我来说没有意义。 我认为(g++(编译器仍然会选择第一个专业化。
有人能解释为什么会发生这种情况的规则吗?
我相信你正在观察由cppreference/SFINAE的这句话引起的行为:
只有函数类型或其模板参数类型的直接上下文中的类型和表达式中的故障才是 SFINAE 错误。如果对替换类型/表达式的计算导致副作用,例如实例化某些模板专用化、生成隐式定义的成员函数等,则这些副作用中的错误将被视为硬错误。
一个最小的例子:
template <typename T>
struct has_foo
{
using foo_t = decltype(T{}.foo());
};
template <typename T> void f(T&&) { }
// SFINAE error => no compilation error:
template <typename T> decltype(T{}.foo()) f(T&&) { }
// non-SFINAE error => hard error:
template <typename T> typename has_foo<T>::foo_t f(T&&) { }
int main()
{
f(1);
}
您的代码基本上表现相同,只是您ArithmeticType
has_foo
至于带有auto
的返回类型扣除,请参阅,例如:SFINAE 与 C++14 返回类型扣除。
具有与上述相同has_foo
的工作示例:
#ifndef DEFINE_THIS_SYMBOL_TO_CAUSE_COMPILATION_ERROR
void f(int) { }
#endif
// no SFINAE => viable candidate
template <typename T> auto f(T&&)
{
return typename has_foo<T>::foo_t{};
}
int main()
{
f(1);
}
如果定义了void f(int) { }
,则匹配效果更好,并且不会实例化模板化f
。
第二个模板的问题在于返回值的扣除:
template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const D2 x2)
当您尝试实例化ArithmeticType<std::complex<double>, std::complex<float> >
时
第二种operator+
类型推导出为: D1:double
, D2:std::complex<float>
.然后,您尝试使用D1=double
、D2=std::complex<float>
来实例化ArithmeticType
。反过来,这又试图推断出double
和std::complex<float>
的operator+
类型。没有这样的函数,你无法编译。
- C++模板选择 - 不寻常的情况
- C 结构具有CHAR数组以不寻常的方式初始化为零
- 以不寻常的方式创建指针
- Box2D不寻常的错误.为什么 0阻止错误
- C++ 今天的多线程,C++ 11 的不稳定情况 - 书籍建议
- 布尔表达的不寻常使用
- 未定义的参考C ,不寻常的情况
- C++可变参数模板不寻常的例子
- Python 和 C++ 程序之间的不寻常速度差异
- C++中不寻常的iostream事件
- C++如何替换代码中不寻常的引号
- 连接(以一种不寻常的方式)信号到插槽
- TaskDialogIndirect返回一个不寻常的错误代码
- 将 istream 中的字符回显到不寻常的"device"
- 如何根据不寻常数字的数量对数组进行排序
- 微控制器显示驱动程序需要在C或c++中进行不寻常的字符串连接
- 这段c++代码是如何处理不寻常的单个布尔语句的?
- c++中不寻常的FOR语句形式
- 为什么printf()在递归函数中显示不寻常的行为
- c++中不寻常的类型定义