enable_if的句法模式

时间:2015-12-01 20:11:07

标签: c++ gcc clang language-lawyer enable-if

我已经以这种近似的方式使用enable_if与各种版本的GCC(最多5.2):

template< bool b, std::enable_if_t< b >... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b >... >
void fn() { std::cout << 2 << std::endl; }
// ...
fn< true >();
fn< false >();

但是,事实证明,Clang 3.7不接受这个(&#34;调用&f;&#39; fn&#39;是模棱两可的&#34;)。

Q1。谁是对的,为什么?

当然还有其他方法可以做到,但我有点不喜欢

template< bool b >
std::enable_if_t< b, void > fa() { std::cout << 1 << std::endl; }
// ...

及其用于使函数签名的正常部分的可读性更低,并且

template< bool b, std::enable_if_t< b, int > = 0 >
void fd() { std::cout << 1 << std::endl; }
// ...

涉及不相关的元素(类型和值)。

Q2。使用enable_if / enable_if_t的其他(正确,更易读,更少hack /怪异)的方法是什么?

3 个答案:

答案 0 :(得分:3)

根据标准 14.1 / p7模板参数[temp.param] Emphasis Mine ):

  

非类型模板参数不得声明为浮点,类或 void类型

因此,您的代码段格式不正确。因此,GCC在这方面是错误的。

但是,如果您更改为:

template< bool b, std::enable_if_t< b, int>... >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int>... >
void fn() { std::cout << 2 << std::endl; }

取消限制,此代码是合法的,应该被接受。显然,似乎Clang也拒绝这个代码。恕我直言,这是一个Clang bug。

我发现有类似的错误报告23840

现在对于实际部分,我不知道这是否实用/不那么ha / /不那么奇怪,但你可以做到以下几点:

template< bool b, std::enable_if_t< b, int> = 0 >
void fn() { std::cout << 1 << std::endl; }
template< bool b, std::enable_if_t< !b, int> = 0 >
void fn() { std::cout << 2 << std::endl; }

答案 1 :(得分:3)

我不确定我是否会在这里使用enable_if。你并没有试图限制一个过载集,所以我称之为反偶像。

简单的专业化似乎工作正常:

template <bool> void fn();
template <> void fn<true>() { std::cout << "true fn\n"; }
template <> void fn<false>() { std::cout << "false fn\n"; }

答案 2 :(得分:1)

  

Q2。还有其他(正确的,更易读,更少hackish /怪异的)使用enable_if / enable_if_t的方法吗?

可以说,这更具可读性,而且不那么神圣了?

#include <iostream>
#include <type_traits>


template< bool b >
auto fn() -> std::enable_if_t<b>
{
    std::cout << 1 << std::endl;
}

template< bool b>
auto fn() -> std::enable_if_t<!b>
{
    std::cout << 2 << std::endl;
}
// ...


auto main() -> int
{
    fn< true >();
    fn< false >();
    return 0;
}

这是另一种可以被认为更具表现力的方式:

#include <iostream>
#include <type_traits>

template <bool b> using When = std::enable_if_t<b, bool>;
template <bool b> using Unless = std::enable_if_t<!b, bool>;

template< bool b, When<b> = true>
void fn2()
{
    std::cout << 1 << std::endl;
}

template< bool b, Unless<b> = true>
void fn2()
{
    std::cout << 2 << std::endl;
}

auto main() -> int
{
    fn2< true >();
    fn2< false >();
    return 0;
}

...或者这样的事情更有表现力?

template <bool b> using Eval = std::integral_constant<bool, b>;

template<bool b>
void fn3()
{
    struct fn3_impl
    {
        static void when(std::true_type)
        {
            std::cout << 1 << std::endl;
        }

        static void when(std::false_type)
        {
            std::cout << 2 << std::endl;
        }
    };

    fn3_impl::when(Eval<b>());
}