Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
291 views
in Technique[技术] by (71.8m points)

c++ - Conditional compile-time inclusion/exclusion of code based on template argument(s)?

Consider the following class, with the inner struct Y being used as a type, eg. in templates, later on:

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

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

Now, this example will obviously not compile, with the error that the second X<I>::Y has already been defined or that it has too many template parameters.
I'd like to resolve that without (extra) partial specialization, since the int I parameter isn't the only one and the position of it can differ in different partial specializations (my actual struct looks more like this, the above is just for simplicity of the question), so I'd like one class fits every I solution.


My first thought was obviously enable_if, but that seems to fail on me, eg. I still get the same errors:

// assuming C++11 support, else use boost
#include <type_traits>

template<int I>
class X{
  template<class T1, class = std::enable_if<I==1>::type>
  struct Y{};

  template<class T1, class T2, class = std::enable_if<I==2>::type>
  struct Y{};
};

So, since enable_if fails, I hope there is another way to achieve the following compile time check:

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{};
  }
};

It would just be to save me a lot of code duplication, but I'd be really happy if it was somehow possible.
Edit: Sadly, I can't use the obvious: variadic templates, as I'm using Visual Studio 2010, so only the C++0x stuff that is supported there I can use. :/

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are two problems here:

  1. enable_if works with partial specialization, not primary templates.
  2. The number of externally-visible arguments is determined by the primary template, of which there may be only one.

Answer 1.

As you suggested in chat, a linked list of templates can emulate the variadic parameter pack.

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;
  };
};

If you end up with next::next::next garbage, it's easy to write a metafunction, or use Boost MPL.


Answer 2.

The different-arity templates can be named similarly but still stay distinct if they are nested inside the SFINAE-controlled type.

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;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...