Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.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++;模板选择-异常情况_C++_Templates - Fatal编程技术网

C++ C++;模板选择-异常情况

C++ C++;模板选择-异常情况,c++,templates,C++,Templates,我有以下定义 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>

我有以下定义

  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);
  }
这对我来说很有意义:
y
属于
std::complex类型

现在,随着添加复杂类型和浮动类型的缩进,我添加了
操作符+
模板的专门化,使代码变得

  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);
  }

模板类算术类型{
公众:
T1-x1;
t2x2;
类型定义(x1+x2)类型的类型;
};
模板内联
复杂的
运算符+(常数std::complex&x1,常数std::complex&x2){
D1 x1r=实(x1);
D1 x1i=imag(x1);
D2 x2r=实际值(x2);
D2-x2i=imag(x2);
返回std::complex(x1r+x2r,x1i+x2i);
}
模板内联
复杂的
运算符+(常数标准::复数&x1,常数D2 x2){
D1 x1r=实(x1);
D1 x1i=imag(x1);
返回std::complex(x1r+x2,x1i+x2);
}
我运行与以前相同的代码,但现在我得到一个编译错误,因为编译器试图使用第二个专门化,而不是第一个。这对我来说毫无意义。我认为(g++)编译器仍然会选择第一个专门化


有人能解释为什么会出现这种情况吗?

第二个模板的问题是返回值的扣除:

template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const D2 x2)
模板内联
复杂的
运算符+(常数标准::复数&x1,常数D2 x2)
当您尝试实例化算术类型时

第二种
运算符+
类型推断为:
D1:
double
,D2:
std::complex
。然后尝试用
D1=double
D2=std::complex
实例化
ArithmeticType
。这反过来又试图推断
double
std::complex
运算符+
的类型。没有这样的函数,您无法编译。

我相信您正在观察由以下引用引起的行为:

只有函数类型或其模板参数类型的直接上下文中的类型和表达式失败才是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);
}

如果定义了
void f(int){}
,则匹配更好,并且模板化的
f
不会实例化。

请注意:
typeof
是非标准的。您应该使用
decltype
代替它。如何调用运算符+?你得到了什么错误代码?@IgorR。我使用
算术类型::类型y
在第一种情况下有效,但当我添加第二个模板专门化时,它尝试使用第二个模板,但失败了。请参见下面@Divinas给出的错误解释,但为什么它使用第二个模板而不是第一个模板?第二个模板可以很好地编译其他代码,比如
arithmetrictype::Type
我相信这是在选择可行的候选代码时发生的。因为运算符+重载,所以它们都被认为是可行的。为了决定使用哪一个函数(如果需要的类型转换较少,则应该是更专业的函数),必须知道整个函数签名。有趣的是,如果您将返回类型声明为自动,这似乎可以编译。我仍在试图弄清楚确切的原因,一旦我发现,我会更新我的答案。让我看看我是否理解正确。在我的例子中,并不是编译器选择了第二个模板化专门化而不是第一个,而是在决策过程中遇到了一个错误,这是评估第二个模板化专门化的副作用。在研究过程中,我发现了同样的错误(你比我解释得更好)。不过我还是没有拿到汽车箱。我认为自动返回类型是在非即时上下文中计算的-为什么这不会导致一个硬错误?@divinas我猜使用
auto
,返回类型根本不会计算,除非选择相应的函数定义作为最佳候选。这也是我的猜测,但找不到任何支持该猜测的文件(也没有反驳):(
template <typename D1, typename D2> inline
std::complex<typename ArithmeticType<D1,D2>::Type>
operator+(const std::complex<D1>& x1, const D2 x2)
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);
}
#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);
}