我想专门针对一个类的子集的函数:具有某个静态数据成员变量,并且此类变量仅具有某些可能的值。

下面的代码说明了这个意图,但是除非我注释掉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_typestd::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>>::valuetrue还是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/

10-11 23:17