1

So, I have this templatized function (which I know is ugly to look at.)

My intention was not to default the template parameter though, my intention was to create a typename derived from T that could be used in caster that the user could not assign to.

My question is how do I create a typename for a templatized function which the user cannot pass as an argument?

As an example:

template <typename T>
typename R = std::conditional<sizeof(T) == 4, char, short>;
R foo(T bar){return R(bar);}

Clearly this code doesn't compile, but that's the behavior I'd like to accomplish. Is a functor the only way to do this?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288

2 Answers2

1

One possibility is to use using type alias instead of typename. The following code compiles on the compiler I tested (remember to enable -std=c++11 flag).

#include <type_traits>
#include <iostream>

// C++11
template <typename T>
using R = typename std::conditional<sizeof(T) == 4, char, short>::type;

template <typename T>
R<T> foo(T bar){return R<T>(bar);}

int main() {
  std::cout << foo(13.0) << std::endl;
  return 0;
}

In C++14, you can use the conditional_t trait, which is even simpler.

// C++14
template <typename T>
using R = std::conditional_t<sizeof(T) == 4, char, short>;
Ying Xiong
  • 4,578
  • 8
  • 33
  • 69
  • It works, but I don't like this solution very much because it introduces a new global name. If this `R` template is useful in its own right, then this is a fine solution but if it's only to save some typing with the function declaration, I'd be reluctant to globally introduce a new type name. Definitely not one with such a common / short name. Putting the helper type in its own namespace could help mitigate the problem a little. – 5gon12eder Feb 23 '15 at 19:05
  • @YingXiong I am unable to get this to work on Visual Studio 2013 or gcc 4.92. Just putting this in `main` as test code should fail: `std::cout << foo(13.0) << std::endl;` gcc says: "error: cannot bind 'std::ostream {aka std::basic_ostream}' lvalue to 'std::basic_ostream&&'" – Jonathan Mee Feb 23 '15 at 19:16
  • @JonathanMee You are right, what I had before failed to compile with your test case, sorry. I update my answer to fix the issue -- basically you should `using` the `::type` of `std::conditional` trait, not the trait itself. Please also note @5gon12eder's comment above, which I totally agree. – Ying Xiong Feb 23 '15 at 20:23
1

In C++14, this is elegantly solved using return type deduction.

// C++14
#include <type_traits>

template <typename T>
decltype(auto)
foo(T bar)
{
  using R = std::conditional_t<sizeof(T) == 4, char, short>;
  return static_cast<R>(bar);
}

In C++11, you'd have to repeat the type computation.

// C++11
#include <type_traits>

template <typename T>
typename std::conditional<sizeof(T) == 4, char, short>::type
foo(T bar)
{
  using R = typename std::conditional<sizeof(T) == 4, char, short>::type;
  return static_cast<R>(bar);
}

This can be shortened a little by using decltype to figure out the type.

// C++11
#include <type_traits>

template <typename T>
typename std::conditional<sizeof(T) == 4, char, short>::type
foo(T bar)
{
  using R = decltype(foo(bar));
  return static_cast<R>(bar);
}

But frankly, what is wrong with using a simple default type parameter?

// C++11
#include <type_traits>

template <typename T,
          typename R = typename std::conditional<sizeof(T) == 4, char, short>::type>
R
foo(T bar)
{
  return static_cast<R>(bar);
}

Note that I have replaced the value initialization of R in your return statement with a static_cast to silence the compiler warning about the narrowing conversion. Are you sure that this is what you want, though?

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
  • @JonathanMee Since C++11, you can use `template auto foo(T t, U u) -> decltype(t + u) { return t + u; }`. This is a *trailing return type* but no *return type deduction*. Since C++14, you can also use `template decltype(auto) foo(T t, U u) { return t + u; }` which is merely syntactic sugar but really great for reducing redundancy. – 5gon12eder Feb 23 '15 at 18:45