问题描述
我想专门针对一个类子集的函数:具有某个静态数据成员变量,并且该变量仅具有某些可能的值.
I want to specialize a function for a subset of classes which: have a certain static data member variable, and such variable has only certain possible values.
下面的代码说明了这个意图,但是除非我注释掉与main
中与B
类相关的行,否则它不会编译.这是因为code
不是Bx
类的成员,但是如果模板参数具有code
成员变量,则enable_if
条件有效.我该如何修改?
The code below illustrates the intent, but it does not compile unless I comment out the lines related to the B
classes in main
. This is because code
is not a member of the Bx
classes, but the enable_if
condition is valid if the template argument has a code
member variables. How should I modify it?
不幸的是,我使用的是非常老的编译器,因此不支持C ++ 11:我使用选项-std=c++03
进行编译.
Unfortunately I work with very old compilers, hence no support for C++11: I compile with the option -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开始的所有语言改进.
The real problem is that you need a C++03 solution, so you can use SFINAE but not all language improvement that are available starting from C++11.
无论如何,我向您提出一个像您一样(也许更多)的难题,但是完全免费的解决方案.
Anyway, I propose you a solution that is convoluted like yours (maybe more) but is completely boost free.
如果您定义了一个普通的布尔包装器(可以粗略地替代C ++ 11 std::true_type
和std::false_type
)
If you define a trivial bool wrapper (that can roughly substitute the C++11 std::true_type
and 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
相同)
and if you define a enable_if
type traits (the same as the 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()
功能
you can SFINAE enable/disable your foo()
functions
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示例
The following is a full working C++98 example
#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类,但我想您可以按如下方式修改您的代码(以几乎作为我的无助解决方案工作)
I don't know the boost classes your using but I suppose you can modify your code (to works almost as my no-boost solution) as follows
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()
的第一个版本或第二个版本.
Well... when you write foo(A1<0>())
, the compiler must understand if cond<A1<0>>::value
is true
or false
to enable the first version of foo()
or the second one.
因此,编译器必须实现cond<A1<0>>
.但是没有cond
模板类仅接收类型名.无论如何,编译器会发现
So the compiler must implement cond<A1<0>>
. But there isn't a cond
template class that receive only a typename. Anyway, the compiler find that
template <typename, typename = bool_wrapper<true> >
struct cond;
使用第二个模板参数的默认值进行匹配.
matches using the default value for the second template parameter.
别无选择,所以没有歧义,所以cond< A<1> >
成为cond< A<1>, bool_wrapper<true> >
There aren't alternative, so there isn't ambiguity, so cond< A<1> >
become cond< A<1>, bool_wrapper<true> >
现在,编译器必须在cond<typename, typename>
的主版本(从bool_wrapper<false>
继承的版本)和专业化版本(从bool_wrapper<true>
继承的版本)之间进行选择.
Now the compiler must choose between the main version of cond<typename, typename>
(the one that inherit from bool_wrapper<false>
) and the specialization (the one that inherit from bool_wrapper<true>
).
cond< A<1>, bool_wrapper<true> >
当然可以匹配主要版本,但是也可以匹配专业化版本?如果也匹配该专业化,则编译器必须优先使用该专业化.
cond< A<1>, bool_wrapper<true> >
surely matches the main version, but matches also the specialization? If matches the also the specialization, the compiler must prefer the specialization.
因此,我们需要查看cond< A<0>, bool_wrapper<true> >
是否与专业匹配.
So we need to see if cond< A<0>, bool_wrapper<true> >
matches the specialization.
使用A<0>
作为T
,我们可以使专业化成为
Using A<0>
as T
, we have that the specialization become
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>
继承.
So cond< A<0> >
, that is cond< A<0>, bool_wrapper<true> >
, matches only the main version of cond<typename, typename>
, so inherit from bool_wrapper<false>
.
现在我们来看一下cond< A<1> >
.
对于cond< A<0> >
,唯一与cond< A<1> >
匹配的模板cond
是cond<typename, typename>
,第二个typename
具有默认值.
As for cond< A<0> >
, the only template cond
that matches cond< A<1> >
is cond<typename, typename>
with the second typename
with the default value.
所以cond< A<1> >
是cond< A<1>, bool_wrapper<true> >
.
但是cond< A<1>, bool_wrapper<true> >
仅匹配cond<typename, typename>
的主要版本还是专业化?
But cond< A<1>, bool_wrapper<true> >
matches only the main version of cond<typename, typename>
or also the specialization?
我们可以看到,使用A<1>
作为T
,我们的专业化成为了
We can see that using A<1>
as T
, we have that the specialization become
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> >
,又名cond< A<1>, bool_wrapper<true>
,cond<typename, typename>
的两个版本都匹配,因此编译器必须选择特殊化,因此cond< A<1> >
继承自bool_wrapper<true>
.
So, for cond< A<1> >
, AKA cond< A<1>, bool_wrapper<true>
, both versions of cond<typename, typename>
match, so the compiler must choose the specialization, so cond< A<1> >
inherit from bool_wrapper<true>
.
这篇关于使用enable_if来仅匹配具有特定静态数据成员且仅具有特定值的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!