9

I want to define a variable for which the type depends on some condition. I want something like this:

typedef typename enable_if<cond, int>::type Type;
typedef typename enable_if<!cond, double>::type Type;

But the conpiler says I redefined the type.

How can I do this?

Niall
  • 30,036
  • 10
  • 99
  • 142
maple
  • 1,828
  • 2
  • 19
  • 28

2 Answers2

13

Can I use enable_if together with typedef?

No you can't. std::enable_if leaves the type undefined if the condition is false. Only if the condition is true, is the member type is defined;

template< bool B, class T = void >
 struct enable_if;

If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef.

For the typedef to work correctly, it needs a type for both cases, when the condition is true and when it is false. enable_if is implemented to assist in scenarios related to SFINAE.

So then

How can I do this?

Use std::conditional. Conditional will contain a member typedef (type) for both the true and false result of the condition.

template< bool B, class T, class F >
 struct conditional;

Provides member typedef type, which is defined as T if B is true at compile time, or as F if B is false.

Hence, the following would suffice;

typedef typename std::conditional<cond, int, double>::type Type;

Or the more terse;

using Type = std::conditional_t<cond, int, double>;
Niall
  • 30,036
  • 10
  • 99
  • 142
  • is it really not legal to use SFINAE with typedef, e.g. `template class C { typedef std::enable_if::value, blah> type; };`? – Flexo Jul 18 '16 at 16:44
  • Not really, see here; https://godbolt.org/g/2YT04Q. I've also not really seen it outside the immediate context of the template deduction. The issue is what happens when the condition is false, the typedef has no type to alias. SFINAE is used to deal with overload resolution of function templates, http://en.cppreference.com/w/cpp/language/sfinae. – Niall Jul 18 '16 at 18:47
8

You need to use std::conditional:

#include <type_traits>

// c++11:
typedef typename std::conditional<cond, int, double>::type Type;

// c++14:
typedef std::conditional_t<cond, int, double> Type;

Also note that since c++11 you can use the using keyword for type and template aliases (a bit cleaner in my opinion):

// c++11
using Type = typename std::conditional<cond, int, double>::type;

// c++14
using Type = std::conditional_t<cond, int, double>;
Holt
  • 36,600
  • 7
  • 92
  • 139