0

Kindof similar to Conditional compile-time inclusion/exclusion of code based on template argument(s)?.

(BTW Answer 2 in above question does not compile at all)

(C++11 and above)

I the following class description, would like Outer::Inner<...> to be a type, so as to used as template parameters, etc.

template<typename T>
struct Outer {
  __enable_if__(cond_1<T>()) {
    // Does not compile if T fails cond_1
    template<typename> Inner { ... }; 
  }
  __enable_if__(cond_2<T>()) {
    // Does not compile if T fails cond_2
    template<typename> Inner { ... }; 
  }
};

I could only think of sth. like below.

#include <type_traits>

struct BaseA { static constexpr int va = 111; };
struct BaseB { static constexpr int vb = 222; };

struct C : public BaseA {};
struct D : public BaseB {};

template<typename T>
struct Outer {
  template<typename, int selector> struct InnerImpl;

  template<typename S> struct InnerImpl<S, 1> { static constexpr int v = T::va; };
  template<typename S> struct InnerImpl<S, 2> { static constexpr int v = T::vb; };

  static constexpr int computeSelector() {
    // Could be less horrible with C++14 constexpr functions
    // std::is_base_of acts as a demo of complex compile-time conditions
    return std::is_base_of<BaseA, T>::value + std::is_base_of<BaseB, T>::value * 2;
  } // **1

  template<typename S> using Inner = InnerImpl<S, computeSelector()>;
};

The problem is that this way it is not extendable at all.

Outer is dependent to all possible T, which could easily lead to circular header dependency.

Is there any solution that Outer is not dependent to T?

Community
  • 1
  • 1
user2771324
  • 307
  • 3
  • 13
  • 1
    Do you only need two potential implementations of `Inner`? In what way do you want it to be extendable? – Jason R Nov 18 '16 at 17:17
  • More than two potential implementations. In the real scenario, BaseA, BaseB and Outer lives in different headers (and logically different modules). Thus I want to eliminate the dep that Outer deps on every involved types. – user2771324 Dec 02 '16 at 08:34
  • What I desire: if type Outer is not used in a translations unit, the translation unit does not have to include all relavant headers for BaseA, BaseB, etc. – user2771324 Dec 02 '16 at 08:34

1 Answers1

0

Not sure to understand your problem but I've tried to semplify your example.

What's wrong with the following solution?

#include <iostream>
#include <type_traits>

struct BaseA { static constexpr int va = 111; };
struct BaseB { static constexpr int vb = 222; };

struct C : public BaseA {};
struct D : public BaseB {};

template<typename T>
struct Outer
 {
   template <typename S, bool B = true>
   struct InnerI;

   template <typename S>
   struct InnerI<S, std::is_base_of<BaseA, T>::value>
    { static constexpr int v { T::va }; };

   template <typename S>
   struct InnerI<S, std::is_base_of<BaseB, T>::value>
    { static constexpr int v { T::vb }; };

   template <typename S>
   using Inner = InnerI<S>;
 };


int main()
 {
   std::cout << Outer<C>::Inner<int>::v    << std::endl;    // print 111
   std::cout << Outer<D>::Inner<long>::v   << std::endl;    // print 222
   // std::cout << Outer<int>::Inner<char>::v << std::endl; // compilation error
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • What I desire: if type Outer is not used in a translations unit, the translation unit does not have to include all relavant headers for BaseA, BaseB, etc. std::is_base_of requires definition of parameter type, which will introduce header dependency. – user2771324 Dec 02 '16 at 08:35