user3770392
user3770392

Reputation: 473

Dependent type automatic deduction

is it possible to do something like:

template<class T, T type>
constexpr auto f(/* type used in some way... */) // -> decltype (etc. in case of C++11)
  {
  return std::integral_constant<T,t>{};
  }

constexpr auto z = f(3); // z is deduced as an integral_constant<int,3>;

It's for sure not possible using a runtime value, but 3 in this case is a compile time value. Maybe someone knows some trick I'm not aware of...

[edit] constexpr auto z2 = f<3>(); // This would be ok too

I just would like to avoid to repeat the type..

Upvotes: 1

Views: 198

Answers (3)

AndyG
AndyG

Reputation: 41092

In C++11 and C++14 this is impossible as per

§14.8.2.5 [temp.deduct.type] 13 and 14

A template type argument cannot be deduced from the type of a non-type template-argument. [Example:

template<class T, T i> void f(double a[10][i]); 
int v[10][20]; 
f(v); // error: argument for template-parameter T cannot be deduced 

—end example ]

So you are forced to specify a type. e.g. f<int, 3>(/*...*/)

I give full credit to @Barry for teaching me this in his answer to my last question

Demo

Upvotes: 1

W.F.
W.F.

Reputation: 13988

Since c++11 you can declare your own literals (I used here std::index_sequence and it's c++14 but you can easily find c++11 implementation of aforesaid):

#include <utility> // for std::index_sequence and std::size_t

constexpr std::size_t ipow(std::size_t base, int exp, std::size_t result = 1) {
  return exp < 1 ? result : ipow(base*base, exp/2, (exp % 2) ? result*base : result);
}

constexpr std::size_t vdot(std::index_sequence<>, std::index_sequence<>) {
    return 0;
}

template <std::size_t C, std::size_t... Cs, std::size_t I, std::size_t... Is>
constexpr std::size_t vdot(std::index_sequence<C, Cs...>, std::index_sequence<I, Is...>) {
    return C*ipow(10, I) + vdot(std::index_sequence<Cs...>{}, std::index_sequence<Is...>{});
}

template <char... Cs>
std::integral_constant<std::size_t, vdot(std::index_sequence<static_cast<std::size_t>(Cs - '0')...>{}, std::make_index_sequence<sizeof...(Cs)>{})> operator ""_ic() {
    return {};
}

int main() {
   auto ic = 3_ic;
   static_cast<void>(ic);
}

[live demo]

Upvotes: 2

Vittorio Romeo
Vittorio Romeo

Reputation: 93264

You can use an auto template parameter in C++17:

template <auto T>
constexpr auto f()
{
    return std::integral_constant<decltype(T), T>{};
}

Usage:

f<3>(); // integral_constant<int, 3>

Alternatively, you need to wrap your value in a compile-time friendly way:

template <int X>
struct int_ 
{ 
    using type = int;
    static constexpr value = X; 
};

template <typename T>
constexpr auto f(T)
{
    return std::integral_constant<typename T::type, T::value>{};
}

Usage:

f(int_<3>{});

Upvotes: 2

Related Questions