【问题标题】:How to use std::enable_if with a condition which itself depends on another condition?如何将 std::enable_if 与本身取决于另一个条件的条件一起使用?
【发布时间】:2015-03-17 22:54:54
【问题描述】:

我有一种情况需要区分两个重载,比如foo,使用std::enable_if。赋予std::enable_if 本身的条件取决于foo 模板参数的依赖类型。

使用std::enable_if 表达这一点的最佳方式是什么?

以下测试代码是我目前所拥有的。我意识到除了std::enable_if 之外可能还有更好的方法来实现我在测试代码中想要的行为。但是,以下是我的用例的简化版本,它本身需要std::enable_if

#include <type_traits>
#include <cassert>

struct bar
{
  using baz = int;
};

template<class T> struct is_bar : std::false_type {};
template<> struct is_bar<bar> : std::true_type {};

template<class Bar>
struct baz_type
{
  using type = typename Bar::baz;
};


template<class T>
typename std::enable_if<
  std::is_integral<
    typename baz_type<T>::type
  >::value,
  int
>::type
  foo(T x)
{
  return 7;
}

template<class T>
typename std::enable_if<
  !is_bar<T>::value,
  int
>::type
  foo(T x)
{
  return 13;
}

int main()
{
  assert(foo(bar()) == 7);
  assert(foo(0) == 13);

  return 0;
}

编译器输出:

$ g++ --version ; echo ; g++ -std=c++11 repro.cpp 
g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


repro.cpp: In instantiation of ‘struct baz_type<int>’:
repro.cpp:29:3:   required by substitution of ‘template<class T> typename std::enable_if<std::is_integral<typename baz_type<Bar>::type>::value, int>::type foo(T) [with T = int]’
repro.cpp:49:3:   required from here
repro.cpp:18:33: error: ‘int’ is not a class, struct, or union type
   using type = typename Bar::baz;

此代码无法编译,因为foo 的第一个重载中使用的enable_if 取决于嵌套类型T::baz。因为int没有这个嵌套类型,所以代码是非法的。

表达我想要的正确方式是什么?

【问题讨论】:

  • 你能让baz_type 成为别名模板而不是类模板吗?
  • 另一种方法是使用多个enable_ifs,例如使用默认模板参数。第一个应该检查is_bar,然后第二个可以使用baz_type&lt;T&gt;::type。标准要求它们按词汇顺序进行评估。
  • @DanielFrey 耸耸肩请给我点赞。虽然我不认为它可读性很强,至少在this answer 之后不会。

标签: c++ templates c++11 metaprogramming enable-if


【解决方案1】:

当我在 Coliru 上写下以下内容时,@dyp 已经在他的评论中展示了重要的部分。以下是可行的,恕我直言,可读性强:

template<
    class T,
    typename=typename std::enable_if<is_bar<T>::value>::type,
    typename=typename std::enable_if<std::is_integral<typename baz_type<T>::type>::value>::type
>
int foo(T x)
{
  return 7;
}

template<
    class T,
    typename=typename std::enable_if<!is_bar<T>::value>::type
>
int foo(T x)
{
  return 13;
}

Live example

对于 C++14,可以使用 std::enable_if_t 来使其更短。

【讨论】:

  • 感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-17
  • 1970-01-01
  • 2021-08-30
  • 2014-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多