我想专门针对一个类的子集的函数:具有某个静态数据成员变量,并且此类变量仅具有某些可能的值。
下面的代码说明了这个意图,但是除非我注释掉B
中与main
类相关的行,否则它不会编译。这是因为code
不是Bx
类的成员,但是如果template参数具有enable_if
成员变量,则code
条件有效。我应该如何修改?
不幸的是,我使用的是非常老的编译器,因此不支持C++ 11:我使用-std=c++03
选项进行编译。
谢谢
#include <iostream>
#include <boost/core/enable_if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/bool.hpp>
using std::cout;
using namespace boost;
using namespace boost::mpl;
template <int N> struct A1 { static const int code = N; };
template <int N> struct A2 { static const int code = N; };
// ... other classes with static data member 'code'
template <int N> struct AN { static const int code = N; };
struct B1{};
struct B2{};
// ... other classes potentially passd as argument to the foo function
struct BN{};
template <typename T>
struct Condition : or_<bool_<T::code == 1>, bool_<T::code == 2> > {};
template <typename T>
typename enable_if<not_<Condition<T> >, void>::type
foo(const T& arg) { cout << "This class does not have a static member code or its value is not 1 or 2\n"; }
template <typename T>
typename enable_if<Condition<T>, void>::type
foo(const T& arg) { cout << "This class has a static member code and its value is " << T::code << "\n"; }
int main()
{
foo(A1<0>()); // this should match the 1st version of foo
foo(A2<1>()); // this should match the 2nd version of foo
foo(AN<2>()); // this should match the 2nd version of foo
foo(B1()); // this should match the 1st version of foo
foo(BN()); // this should match the 1st version of foo
}
最佳答案
真正的问题是您需要C++ 03解决方案,因此可以使用SFINAE,但不能使用从C++ 11开始的所有可用语言改进。
无论如何,我为您提出了一个像您一样(也许更多)的解决方案,但是完全免费的解决方案。
如果定义一个普通的 bool(boolean) 包装器(可以粗略地替代C++ 11的std::true_type
和std::false_type
)
template <bool B>
struct bool_wrapper
{ static const bool value = B; };
您可以如下定义您的条件
template <typename, typename = bool_wrapper<true> >
struct cond : public bool_wrapper<false>
{ };
template <typename T>
struct cond<T, bool_wrapper<(1 == T::code) || (2 == T::code)> >
: public bool_wrapper<true>
{ };
并且如果您定义了
enable_if
类型特征(与C++ 11 std::enable_if
相同)template <bool, typename = void>
struct enable_if
{ };
template <typename T>
struct enable_if<true, T>
{ typedef T type; };
您可以SFINAE启用/禁用
foo()
函数template <typename T>
typename enable_if<false == cond<T>::value>::type foo (T const & arg)
{ std::cout << "no static member code or value not 1 and not 2\n"; }
template <typename T>
typename enable_if<true == cond<T>::value>::type foo (T const & arg)
{ std::cout << "static member code and its value is " << T::code << "\n"; }
以下是完整的C++ 98示例
#include <iostream>
template <int N> struct A1 { static const int code = N; };
template <int N> struct A2 { static const int code = N; };
// ...
template <int N> struct AN { static const int code = N; };
struct B1{};
struct B2{};
// ...
struct BN{};
template <bool B>
struct bool_wrapper
{ static const bool value = B; };
template <typename, typename = bool_wrapper<true> >
struct cond : public bool_wrapper<false>
{ };
template <typename T>
struct cond<T, bool_wrapper<(1 == T::code) || (2 == T::code)> >
: public bool_wrapper<true>
{ };
template <bool, typename = void>
struct enable_if
{ };
template <typename T>
struct enable_if<true, T>
{ typedef T type; };
template <typename T>
typename enable_if<false == cond<T>::value>::type foo (T const & arg)
{ std::cout << "no static member code or value not 1 and not 2\n"; }
template <typename T>
typename enable_if<true == cond<T>::value>::type foo (T const & arg)
{ std::cout << "static member code and its value is " << T::code << "\n"; }
int main ()
{
foo(A1<0>()); // match the 1st version of foo
foo(A2<1>()); // match the 2nd version of foo
foo(AN<2>()); // match the 2nd version of foo
foo(B1()); // match the 1st version of foo
foo(BN()); // match the 1st version of foo
}
我不知道您使用的boost类,但是我想您可以按如下方式修改您的代码(几乎可以作为我的非boost解决方案使用)
template <typename, typename = bool_<true> >
struct Condition : public bool_<false>
{ };
template <typename T>
struct Condition<T, bool_<(1 == T::code) || (2 == T::code)> >
: public bool_<true>
{ };
-编辑-
OP问
好吧...当您编写
foo(A1<0>())
时,编译器必须了解cond<A1<0>>::value
是true
还是false
才能启用foo()
的第一个版本或第二个版本。因此,编译器必须实现
cond<A1<0>>
。但是没有cond
模板类仅接收类型名称。无论如何,编译器发现template <typename, typename = bool_wrapper<true> >
struct cond;
使用第二个模板参数的默认值进行匹配。
没有选择,所以没有歧义,所以
cond< A<1> >
变成cond< A<1>, bool_wrapper<true> >
现在,编译器必须在
cond<typename, typename>
的主版本(从bool_wrapper<false>
继承的版本)和特化版本(从bool_wrapper<true>
继承的版本)之间进行选择。cond< A<1>, bool_wrapper<true> >
当然可以匹配主要版本,但是也可以匹配特化版本?如果也匹配专业,编译器必须优先使用专业。因此,我们需要查看
cond< A<0>, bool_wrapper<true> >
是否与特化匹配。使用
A<0>
作为T
,我们的特化成为cond< A<0>, bool_wrapper<(1 == A<0>::code) || (2 == A<0>::code)> >
那是
cond< A<0>, bool_wrapper<(1 == 0) || (2 == 0)> >
那是
cond< A<0>, bool_wrapper<false || false> >
那是
cond< A<0>, bool_wrapper<false> >
这与
cond< A<0>, bool_wrapper<true> >
不匹配。因此,
cond< A<0> >
(即cond< A<0>, bool_wrapper<true> >
)仅匹配cond<typename, typename>
的主版本,因此从bool_wrapper<false>
继承。现在我们来看看
cond< A<1> >
。对于
cond< A<0> >
,唯一与cond
匹配的模板cond< A<1> >
是cond<typename, typename>
,第二个typename
具有默认值。因此
cond< A<1> >
是cond< A<1>, bool_wrapper<true> >
。但是
cond< A<1>, bool_wrapper<true> >
只匹配cond<typename, typename>
的主要版本还是特化?我们可以看到,使用
A<1>
作为T
,我们的特化成为cond< A<1>, bool_wrapper<(1 == A<1>::code) || (2 == A<1>::code)> >
那是
cond< A<1>, bool_wrapper<(1 == 1) || (2 == 1)> >
那是
cond< A<1>, bool_wrapper<true || false> >
那是
cond< A<1>, bool_wrapper<true> >
这匹配
cond< A<1>, bool_wrapper<true> >
。因此,对于
cond< A<1> >
和AKA cond< A<1>, bool_wrapper<true>
,两个版本的cond<typename, typename>
都匹配,因此编译器必须选择特殊化,因此cond< A<1> >
继承自bool_wrapper<true>
。关于c++ - 使用enable_if来仅匹配具有特定静态数据成员且仅具有特定值的类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52565407/