如何在本身取决于另一个条件的条件下使用 std::enable_if?
How to use std::enable_if with a condition which itself depends on another condition?
我有一种情况需要使用 std::enable_if
区分两个重载,例如 foo
。 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
没有这个嵌套类型,代码不合法
表达我想要的东西的正确方式是什么?
虽然我在 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;
}
对于 C++14,可以使用 std::enable_if_t
使其更短。
我有一种情况需要使用 std::enable_if
区分两个重载,例如 foo
。 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
没有这个嵌套类型,代码不合法
表达我想要的东西的正确方式是什么?
虽然我在 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;
}
对于 C++14,可以使用 std::enable_if_t
使其更短。