c++ - C++ 模板选择 - 不寻常的情况
问题描述
我有以下定义
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);
}
您的代码基本上表现相同,只是has_foo
您没有ArithmeticType
.
至于使用 的返回类型推导auto
,请参见例如:SFINAE with C++14 return type deduction。
与上述相同的工作示例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
不会实例化模板。
推荐阅读
- c# - 在 Enterprise Architect 中查询以查找工具集及其元素
- exchangewebservices - 在 EWS 托管 API 中获取 Recurrence Master ID
- arrays - 除非明确引用一个字典枚举键,否则编译器会抱怨
- c++ - 隐式转换产生“错误:获取临时地址”(GCC vs clang)
- powerbi - 在 PowerBI 图表中将持续时间显示为“hh:mm:ss”
- angular - 如何将焦点设置在 dxi 项目上
- python - Python csv 导出限制为 8KB?
- c# - 对 BuildHttpClientBase.GetBuildWorkItemsRefsAsync 的调用不会返回由具有利益相关者访问权限的用户创建的工作项
- sharepoint - 在一个应用程序池上运行两个 Web 应用程序有什么用?
- c# - 为什么 Math.Round(3.13732294754486E-12, 2) 为零?