C++ 基于模板参数的有条件编译时包含/排除代码?

C++ 基于模板参数的有条件编译时包含/排除代码?,c++,templates,conditional-compilation,compile-time,C++,Templates,Conditional Compilation,Compile Time,考虑以下类,内部结构Y用作类型,例如稍后在模板中: template<int I> class X{ template<class T1> struct Y{}; template<class T1, class T2> struct Y{}; }; 因此,既然在失败时启用\u,我希望有另一种方法来实现以下编译时检查: template<int I> class X{ __include_if(I == 1){ t

考虑以下类,内部结构
Y
用作类型,例如稍后在模板中:

template<int I>
class X{
  template<class T1>
  struct Y{};

  template<class T1, class T2>
  struct Y{};
};

因此,既然
失败时启用\u,我希望有另一种方法来实现以下编译时检查:

template<int I>
class X{
  __include_if(I == 1){
    template<class T1>
    struct Y{};
  }

  __include_if(I == 2){
    template<class T1, class T2>
    struct Y{};
  }
};
模板
X类{
__如果(I==1),则包括{
模板
结构Y{};
}
__如果(I==2)包含_{
模板
结构Y{};
}
};

这只不过是为了给我节省大量的代码重复,但如果有可能的话,我会非常高兴的。
编辑:遗憾的是,我不能使用显而易见的:可变模板,因为我使用的是Visual Studio 2010,所以我只能使用那里支持的C++0x内容:/

这种方法怎么样?(对不起,俄语)

你能试试下面的内容吗(这不是部分专业化):

模板
X类
{
};
模板
X类
{
模板
结构Y{};
};
模板
X类
{
模板
结构Y{};
};
我怀疑答案是否那么简单

编辑(模拟部分专门化): @Xeo,我能够编译下面的代码,而且似乎已经很满了

template<int I>
struct X
{
  struct Unused {};  // this mocking structure will never be used

  template<class T1, class T2 = Unused>  // if 2 params passed-->ok; else default='Unused'
  struct Y{};

  template<class T1> 
  struct Y<T1, Unused>{}; // This is specialization of above, define it your way
};

int main()
{
  X<1>::Y<int> o1;  // Y<T1 = int, T2 = Unused> called
  X<2>::Y<int, float> o2; // Y<T1 = int, T2 = float> called
}
模板
结构X
{
struct Unused{};//永远不会使用此模拟结构
模板//如果传递了2个参数-->确定;否则默认为未使用
结构Y{};
模板
struct Y{};//这是上面的专门化,按您的方式定义它
};
int main()
{
X::Y o1;//调用了Y
X::Y o2;//调用了Y
}
在这里,你可以互换使用X,X。但在你提到的更广泛的例子中,这是无关紧要的。如果需要,您仍然可以检查
I=1
I=2

给您:

以及守则:

#include <iostream>

template <int I>
struct Traits
{
  struct inner{};
};

template <>
struct Traits<1>
{
  struct inner{
    template<class T1>
    struct impl{
      impl() { std::cout << "impl<T1>" << std::endl; }
    };
  };
};

template <>
struct Traits<2>
{
  struct inner{
    template<class T1, class T2>
    struct impl{
      impl() { std::cout << "impl<T1, T2>" << std::endl; }
    };
  };
};

template<class T>
struct Test{};

template<class T, class K>
struct Foo{};

template<int I>
struct arg{};

template<
  template<class, class> class T,
  class P1, int I
>
struct Test< T<P1, arg<I> > >{
  typedef typename Traits<I>::inner inner;      
};

template<
  template<class, class> class T,
  class P2, int I
>
struct Test< T<arg<I>, P2 > >{
  typedef typename Traits<I>::inner inner;      
};

// and a bunch of other partial specializations

int main(){

  typename Test<Foo<int, arg<1> > >::inner::impl<int> b;
  typename Test<Foo<int, arg<2> > >::inner::impl<int, double> c;
}
#包括
模板
结构特征
{
结构内部{};
};
模板
结构特征
{
结构内部{
模板
结构impl{
impl(){std::cout

struct Test您可以使用元函数(此处:内联
boost::mpl::if_c
,但可以任意复杂)来选择所需的函数。您需要一些脚手架才能使用构造函数,但:

template <int I>
class X {
    template <typename T1>
    class YforIeq1 { /* meat of the class */ };
    template <typename T1, typename T2>
    class YforIeq2 { /* meat of the class */ };
public:
    template <typename T1, typename T2=boost::none_t/*e.g.*/>
    struct Y : boost::mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type {
        typedef typename mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type YBase;
        /* ctor forwarding: C++0x */
        using YBase::YBase;
        /* ctor forwarding: C++03 (runs into perfect fwd'ing problem)*/
        Y() : YBase() {}
        template <typename A1>
        Y(const A1&a1) : YBase(a1) {}
        template <typename A1, typename A2>
        Y(const A1&a1, const A2&a2) : YBase(a1,a2) {}
        // ...
    };
};
模板
X类{
模板
类{/*类的肉*/};
模板
类YforIeq2{/*类的肉*/};
公众:
模板
结构Y:boost::mpl::if_c::type{
typedef typename mpl::if_c::type YBase;
/*ctor转发:C++0x*/
使用YBase::YBase;
/*ctor转发:C++03(遇到完美的转发问题)*/
Y():YBase(){}
模板
Y(常数A1&A1):YBase(A1){}
模板
Y(常数A1和A1,常数A2和A2):YBase(A1,A2){}
// ...
};
};

如果为每个X实例化
YforIeq
N这两个函数都有问题,那么您可以尝试将它们包装为空元函数(这是
mpl::apply
所做的事情)并使用
mpl::eval\u If_c
这里有两个问题:

  • 如果
  • 与部分专用化而不是主模板一起工作,则启用
  • 外部可见参数的数量由主模板决定,其中可能只有一个
  • 答复1。 正如您在聊天中所建议的,模板的链接列表可以模拟可变参数包

    template<int I>
    class X{
      template<class list, class = void>
      struct Y;
    
      template<class list>
      struct Y< list, typename std::enable_if<I==1>::type > {
          typedef typename list::type t1;
      };
    
      template<class list>
      struct Y< list, typename std::enable_if<I==2>::type > {
          typedef typename list::type t1;
          typedef typename list::next::type t2;
      };
    };
    

    +1.有趣的问题。我会在办公时间后尝试回答它:我很乐意。我的想法是,这应该是可能的,因为编译器在编译时知道它需要知道的一切。@Xeo:允许你使用C++0x feautures吗?@Xeo:对不起,这看起来很愚蠢,但是变量模板呢?你可以只统计一下ic_声明包大小。@Matthieu:不傻,很抱歉我没有提供这些信息:现在还不能使用C++0x的可变模板,因为我使用的是Visual Studio 2010.:/我真的希望VC11很快问世,因为这些可变模板对于像这样的东西和密钥习惯用法来说简直太棒了。遗憾的是不适用,因为内部模板struct应该作为一个类型使用,例如在模板中。:/Btw,这让意图变得很好。再想一想,也许这会与一些decltype技巧一起工作。我回家后会尝试。:)这就是我所说的“没有(额外)部分专门化”的意思,因为
    int I
    不是唯一的模板参数,但还有其他参数。我链接到Ideone以了解它的真实外观,为了简化问题,结构被简化了。你能检查编辑过的版本吗?实际上我已经将第二个模板版本作为主版本,第一个版本是第二个版本的专用化一、希望有帮助!我发布了同样的简化代码,但提问者说模板不会像
    template
    @iammilind那么简单,我说它是一个扩展,代码略有不同,在上面,
    I
    的专门化被委托给
    Traits
    类和
    Test
    类使用那就是,在你的回答中,你说的是为每个
    I
    (或
    X
    )专门化
    Test
    ,而OP不愿意这样做。你是对的。很抱歉,我错过了。谢谢你的点评。先生,你能解释一下你的台词“如果使用部分专门化,而不是主要模板,请启用”,为什么不能像OP一样将其用于主模板?非常感谢:)@AngelusMortis部分专门化模板参数被推导出来(§14.5.5.1[temp.class.spec.match])。
    如果在那里工作,则启用,\u,因为替换失败不是错误(SFINAE)主模板没有这样的好处-替换失败是一个错误。
    
    template <int I>
    class X {
        template <typename T1>
        class YforIeq1 { /* meat of the class */ };
        template <typename T1, typename T2>
        class YforIeq2 { /* meat of the class */ };
    public:
        template <typename T1, typename T2=boost::none_t/*e.g.*/>
        struct Y : boost::mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type {
            typedef typename mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type YBase;
            /* ctor forwarding: C++0x */
            using YBase::YBase;
            /* ctor forwarding: C++03 (runs into perfect fwd'ing problem)*/
            Y() : YBase() {}
            template <typename A1>
            Y(const A1&a1) : YBase(a1) {}
            template <typename A1, typename A2>
            Y(const A1&a1, const A2&a2) : YBase(a1,a2) {}
            // ...
        };
    };
    
    template<int I>
    class X{
      template<class list, class = void>
      struct Y;
    
      template<class list>
      struct Y< list, typename std::enable_if<I==1>::type > {
          typedef typename list::type t1;
      };
    
      template<class list>
      struct Y< list, typename std::enable_if<I==2>::type > {
          typedef typename list::type t1;
          typedef typename list::next::type t2;
      };
    };
    
    template<int I>
    class X{
      template<typename = void, typename = void>
      struct Z;
    
      template<typename v>
      struct Z< v, typename std::enable_if<I==1>::type > {
          template<class T1>
          struct Y{};
      };
    
      template<typename v>
      struct Z< v, typename std::enable_if<I==2>::type > {
          template<class T1, class T2>
          struct Y{};
      };
    };
    
    X<1>::Z<>::Y< int > a;
    X<2>::Z<>::Y< char, double > b;