使用静态 constexpr 成员变量作为模板方法参数
Using static constexpr member variables as template method parameters
我试图通过将有关 class 的一些信息定义为静态 constexpr 成员来简化一些模板代码。这是一个简化得多的示例:
template <typename _Tp>
class Test
{
public:
static constexpr bool is_array = std::is_array_v<_Tp>;
template <typename U = _Tp, typename std::enable_if_t<!is_array>>* dummy = nullptr>
void print()
{
std::cout << "It's not an array\n";
}
template <typename U = _Tp, typename std::enable_if_t<is_array>>* dummy = nullptr>
void print()
{
std::cout << "It's an array\n";
}
};
int main()
{
Test<char[]>().print();
Test<char>().print();
}
叮当说
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/type_traits:2385:44: error: no type named 'type' in 'std::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^~~~~
test.cc:11:49: note: in instantiation of template type alias 'enable_if_t' requested here
template <typename U = _Tp, typename = std::enable_if_t<!is_array>>
^
test.cc:26:5: note: in instantiation of template class 'Test<char []>' requested here
Test<char[]>().print();
如果我完全限定 is_array
,它会起作用,如 Test<U>::is_array
,但我有几个模板参数,并且这样做似乎会使它变得更加混乱。
除了使用宏之外,还有什么方法可以满足我的需求吗?
如果您希望 SFINAE 适用于 class 的方法,则必须基于该方法的特定模板参数进行测试(因此 U
,在您的情况下)。
如果你检查is_array
,如果依赖于_Tp
(class的模板参数),而不是来自U
.
但是,如果你至少可以使用 C++14,你可以有模板变量,所以你可以模板化 is_array
template <typename U>
static constexpr bool is_array = std::is_array_v<U>;
这简化了一点
您也可以删除 std::enable_if_t
之前的 typename
(感谢 _t
)并取消 dummy
(未使用)。
下面是一个完整的编译示例
#include <iostream>
#include <type_traits>
template <typename T>
struct Test
{
template <typename U>
static constexpr bool is_array = std::is_array_v<U>;
template <typename U = T,
std::enable_if_t<not is_array<U>>* = nullptr>
void print()
{ std::cout << "It's not an array\n"; }
template <typename U = T,
std::enable_if_t<is_array<U>>* = nullptr>
void print()
{ std::cout << "It's an array\n"; }
};
int main()
{
Test<char[]>().print();
Test<char>().print();
}
另一种方法(可能更好)是使用 bool
模板参数而不是 U
;例如
template <typename T>
struct Test
{
static constexpr bool is_array = std::is_array_v<T>;
template <bool B = is_array,
std::enable_if_t<not B>* = nullptr>
void print()
{ std::cout << "It's not an array\n"; }
template <bool B = is_array,
std::enable_if_t<B>* = nullptr>
void print()
{ std::cout << "It's an array\n"; }
};
我试图通过将有关 class 的一些信息定义为静态 constexpr 成员来简化一些模板代码。这是一个简化得多的示例:
template <typename _Tp>
class Test
{
public:
static constexpr bool is_array = std::is_array_v<_Tp>;
template <typename U = _Tp, typename std::enable_if_t<!is_array>>* dummy = nullptr>
void print()
{
std::cout << "It's not an array\n";
}
template <typename U = _Tp, typename std::enable_if_t<is_array>>* dummy = nullptr>
void print()
{
std::cout << "It's an array\n";
}
};
int main()
{
Test<char[]>().print();
Test<char>().print();
}
叮当说
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/type_traits:2385:44: error: no type named 'type' in 'std::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^~~~~
test.cc:11:49: note: in instantiation of template type alias 'enable_if_t' requested here
template <typename U = _Tp, typename = std::enable_if_t<!is_array>>
^
test.cc:26:5: note: in instantiation of template class 'Test<char []>' requested here
Test<char[]>().print();
如果我完全限定 is_array
,它会起作用,如 Test<U>::is_array
,但我有几个模板参数,并且这样做似乎会使它变得更加混乱。
除了使用宏之外,还有什么方法可以满足我的需求吗?
如果您希望 SFINAE 适用于 class 的方法,则必须基于该方法的特定模板参数进行测试(因此 U
,在您的情况下)。
如果你检查is_array
,如果依赖于_Tp
(class的模板参数),而不是来自U
.
但是,如果你至少可以使用 C++14,你可以有模板变量,所以你可以模板化 is_array
template <typename U>
static constexpr bool is_array = std::is_array_v<U>;
这简化了一点
您也可以删除 std::enable_if_t
之前的 typename
(感谢 _t
)并取消 dummy
(未使用)。
下面是一个完整的编译示例
#include <iostream>
#include <type_traits>
template <typename T>
struct Test
{
template <typename U>
static constexpr bool is_array = std::is_array_v<U>;
template <typename U = T,
std::enable_if_t<not is_array<U>>* = nullptr>
void print()
{ std::cout << "It's not an array\n"; }
template <typename U = T,
std::enable_if_t<is_array<U>>* = nullptr>
void print()
{ std::cout << "It's an array\n"; }
};
int main()
{
Test<char[]>().print();
Test<char>().print();
}
另一种方法(可能更好)是使用 bool
模板参数而不是 U
;例如
template <typename T>
struct Test
{
static constexpr bool is_array = std::is_array_v<T>;
template <bool B = is_array,
std::enable_if_t<not B>* = nullptr>
void print()
{ std::cout << "It's not an array\n"; }
template <bool B = is_array,
std::enable_if_t<B>* = nullptr>
void print()
{ std::cout << "It's an array\n"; }
};