18

I would like to perform a typedef, if and only if a compile-time condition is met. If the condition is not met, no typedef shall be performed at all.

Is that possible in C++11?

Example:

class A {
  std::conditional_typedef<true,int,myType1>; // Performs "typedef int myType1".
  std::conditional_typedef<false,int,myType2>; // Does nothing at all.
};

I am looking for this fictional std::conditional_typedef.

8
  • 3
    Could you provide some example code with that theoretical if(...) typedef ...; ? In particular, what should happen with code that uses the typedef if the typedef isn't "performed" ?
    – Quentin
    Commented Dec 1, 2016 at 9:58
  • 11
    std::enable_if
    – Danh
    Commented Dec 1, 2016 at 10:03
  • 1
    depending on condition specialization may be sufficient...
    – W.F.
    Commented Dec 1, 2016 at 10:04
  • 1
    A simple almost-solution would be to conditionally typedef to the requested type, or to something that will be unusable in most cases, such as void. Would that fit your case ?
    – Quentin
    Commented Dec 1, 2016 at 10:22
  • 3
    There is the venerable #ifdef ? Commented Dec 1, 2016 at 12:55

3 Answers 3

20

Another way can be passing from the specialization of a base class

// foo is a light struct (only a typedef or not at all) that can be
// developed in two versions

template <bool>
struct foo;

template <>
struct foo<true>
 { typedef int myType1; }; // or using myType1 = int;

template <>
struct foo<false>
 { };

template <bool B>
struct bar : public foo<B> // B can be a type_traits value derived
                           // from template arguments for bar
 {
   // potential complex struct or class, developed only one time 
 };


int main()
 {
   bar<true>::myType1 mt1 { 1 };
   // bar<false>::myType1 mt2 { 1 }; error: ‘myType1’ is not a member of ‘bar<false>’
 }
5
  • Using inheritance appears to be a very natural way to solve the task. Commented Dec 1, 2016 at 12:29
  • 1
    Can't one do without the derived bar and directly use foo<true>::myType1 mt1 {1} ?
    – chi
    Commented Dec 1, 2016 at 12:34
  • 5
    @chi - can be done; the advantage of using a base class (IMHO) is that you can develop two different specializations of a simple and light class with only (or without) a typedef; this permit to develop a single version of the derived class that can be complex.
    – max66
    Commented Dec 1, 2016 at 13:06
  • 1
    @max66: Even though this technically use inheritance, I would be tempted to label this as mix-in instead. It's a very natural solution in templates. Commented Dec 1, 2016 at 13:35
  • @MatthieuM. - well... I'm not an expert and I'm bad in labelling but, yes, using templates I find it very natural.
    – max66
    Commented Dec 1, 2016 at 13:48
16

Unfortunately desired syntax can't be possible as names that are passed to the template instantiation have to be already defined. In your case myType1 and myType2 wouldn't name anything from compiler point of view. However if you're not insisting on the syntax you've mentioned you could try to use std::enable_if as follows:

#include <type_traits>

struct A {
    struct myType1: std::enable_if<true, int> { }; //std::conditional_typedef<true,int,myType1>; // Performs "typedef int myType1".
    struct myType2: std::enable_if<false, int> { }; //std::conditional_typedef<false,int,myType2>; // Does nothing at all.

};

int main() {
    A::myType1::type i;
    //A::myType2::type i2; // causes error: no type named 'type' in 'A::myType2'
    (void)i;
}

[live demo]


Edit:

Yet another way that came to my mind (utilizing using with default template parameter):

#include <type_traits>

struct A {
    template <class T = int>
    using myType1 = typename std::enable_if<true, T>::type;
    template <class T = int>
    using myType2 = typename std::enable_if<false, T>::type;
};

int main() {
    A::myType1<> i;
    //A::myType2<> j;
    (void)i;
}

[live demo]

2

Similar to std::enable_if, you could have your class descend from a template that does your typedef if you want to use your own names and not have to do A::mytype1::type. The downside is that you'd have to descend from multiple structs if you want to do this a lot.

namespace impl {
    template<bool, typename> struct A;
    template<typename T> struct A<true, T>{ typedef T mytype1; };
    template<typename T> struct A<false, T> {};
}

struct A : public impl::A<condition, int> {
    //If condition is met, then ::mytype1 will be defined as a typedef int
};

int main() {
    A::mytype1 i; //Will fail if condition wasn't met
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.