在测试SFINAE时,我发现了一些我认为不应该起作用的东西

时间:2017-03-13 20:48:21

标签: c++ c++14 sfinae

我发现了一个有趣的条件函数排除,我是从this site得到的,在测试时我遇到了这个:

#include<type_traits>

namespace detail
{
    enum enabler {};
}

template <int overload, typename Condition>
using EnableIf = std::enable_if_t<Condition::value, detail::enabler>;

template <typename T,
    EnableIf<0, std::is_same<T, int>>...>
    T twice(T t) { return 2 * t; }

template <typename T,
    EnableIf<0, std::is_same<T, float>>...>
    T twice(T t) { return 2 * t; }

int main()
{
    twice(1);
    twice(1.f);
    return 0;
}

这不应该导致编译器错误,因为EnableIf类型在两个函数中是相同的吗?我打算为每个重载使用不同的数字,并且有一个模板类,它将包含启动器枚举,以便它是一个不同的类型,但似乎它是不必要的。这是缺陷还是我错过了什么?

我已经在VC ++(2017)和clang上对此进行了测试。

虽然VC ++编译器并没有抱怨,但显然智能感知并不喜欢它:

enter image description here

这就是我的想法,但不管我是否使用不同的整数,它都会抱怨,甚至不会做我说我要做的事情。

2 个答案:

答案 0 :(得分:3)

  

这不应该导致编译器错误,因为EnableIf类型在两个函数中是相同的吗?

但他们并不相同。一个需要一包std::enable_if_t<std::is_same<T, int>::value, detail::enabler>,另一个需要一包std::enable_if_t<std::is_same<T, float>::value, detail::enabler>。这些是完全不相关的类型,因此您声明了两个不相关的函数模板。实际上,这两种类型中至少有一种是格式错误的,因此它们不能具有相同的类型 - 最好两者都是不正确的。

这很好。不同的数字不仅是不必要的,而且也不会做任何事情 - 别名模板是透明的,因此数字会消失,因为您在实际的类型表达式中没有使用它。

只有当两个EnableIf条件 时,然后才会在两者中以相同的类型(detail::enabler)结束功能。

答案 1 :(得分:0)

看起来我在抽奖时速度太快,并将Barry's answer标记为正确答案。然而,它似乎不太正确,或者至少不清楚。

只要参数不同,函数就可以具有有效的重载。模板函数是相同的,但其签名还包括模板参数。因此,您可以使用相同的参数列表具有相同的函数名称,但使用不同的模板参数,它仍将被视为过载。

因此,如果两个函数都具有相同类型T的可行性,则会发生冲突。

但是,由于EnableIf仅在互斥条件下解析为某种类型,因此即使第二种模板类型将解析为相同类型detail::enabler,第一个模板参数也会是一个不同的类型(即使没有基于函数参数的自动推导,具有相同的函数参数类型,这仍然有效)。因此,这仍然是一个不同的函数重载。

@Barry说std::enable_if_t<std::is_same<T, int>::value, detail::enabler>std::enable_if_t<std::is_same<T, float>::value, detail::enabler>是完全不相关的类型。他有点正确。如果有效,他们会确定完全相同的类型,但他没有提到的是他们在同一时间并不是有效的。