SFINAE在返回类型,但不作为模板参数工作SFINAE在返回类型,但不作为模板参数工作(SFINA

2019-05-06 11:42发布

我已经使用了SFINAE成语了好几次,我习惯了把我std::enable_if<>模板参数,而不是返回类型。 不过,我碰到一些琐碎的情况下也没有工作,我不知道为什么。 首先,这里是我的主:

int main()
{
    foo(5);
    foo(3.4);
}

下面是一个实现foo触发错误:

template<typename T,
         typename = typename std::enable_if<std::is_integral<T>::value>::type>
auto foo(T)
    -> void
{
    std::cout << "I'm an integer!\n";
}

template<typename T,
         typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
auto foo(T)
    -> void
{
    std::cout << "I'm a floating point number!\n";
}

这里是一个代码据说相当于一块正常工作:

template<typename T>
auto foo(T)
    -> typename std::enable_if<std::is_integral<T>::value>::type
{
    std::cout << "I'm an integrer!\n";
}

template<typename T>
auto foo(T)
    -> typename std::enable_if<std::is_floating_point<T>::value>::type
{
    std::cout << "I'm a floating point number!\n";
}

我的问题是:为什么第一个实现的foo触发错误而第二个不触发呢?

 main.cpp:14:6: error: redefinition of 'template<class T, class> void foo(T)' auto foo(T) ^ main.cpp:6:6: note: 'template<class T, class> void foo(T)' previously declared here auto foo(T) ^ main.cpp: In function 'int main()': main.cpp:23:12: error: no matching function for call to 'foo(double)' foo(3.4); ^ main.cpp:6:6: note: candidate: template<class T, class> void foo(T) auto foo(T) ^ main.cpp:6:6: note: template argument deduction/substitution failed: main.cpp:5:10: error: no type named 'type' in 'struct std::enable_if<false, void>' typename = typename std::enable_if<std::is_integral<T>::value>::type> ^ 

编辑

工作代码和错误代码 。

Answer 1:

你应该看看14.5.6.1 Function template overloading其中的函数模板等效定义(C ++ 11标准)。 总之,默认模板参数不考虑,所以在第一种情况下,你有相同的函数模板定义了两次。 在第二种情况,你必须在返回类型中使用(再参照14.5.6.1/4)表达参照模板参数。 由于这种表达签名的一部分,你得到两个不同的函数模板声明,因此SFINAE得到工作的机会。



Answer 2:

= ...模板只是给出了一个默认的参数。 这是不实际的签名,它看起来像的一部分

template<typename T, typename>
auto foo(T a);

两种功能。

根据您的需求,对于这个问题的最通用的解决方案是使用标签调度。

struct integral_tag { typedef integral_tag category; };
struct floating_tag { typedef floating_tag category; };

template <typename T> struct foo_tag
: std::conditional<std::is_integral<T>::value, integral_tag,
                    typename std::conditional<std::is_floating_point<T>::value, floating_tag,
                                               std::false_type>::type>::type {};

template<typename T>
T foo_impl(T a, integral_tag) { return a; }

template<typename T>
T foo_impl(T a, floating_tag) { return a; }

template <typename T>
T foo(T a)
{
  static_assert(!std::is_base_of<std::false_type, foo_tag<T> >::value,
                 "T must be either floating point or integral");
  return foo_impl(a, typename foo_tag<T>::category{});
}

struct bigint {};
template<> struct foo_tag<bigint> : integral_tag {};

int main()
{
  //foo("x"); // produces a nice error message
  foo(1);
  foo(1.5);
  foo(bigint{});
}


Answer 3:

模板中的值工作:

template<typename T,
         typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm an integer!\n";
}

template<typename T,
         typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm a floating point number!\n";
}


文章来源: SFINAE working in return type but not as template parameter