1

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..

Quentin
  • 62,093
  • 7
  • 131
  • 191
user3770392
  • 453
  • 5
  • 12

3 Answers3

2

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>{});
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Thank you for you reply. I forgot to mention that it's a C++11 question. This is one of the reason one should go for C++17, because that code would be the ideal solution! The second approach unfortunately doesn't fit what I'm looking to achieve. I'd like to avoid the creation of structs like int_ – user3770392 Jun 07 '17 at 14:31
2

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]

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • I'll try to go deeper into your solution.. but I don't think is going to work for what I need: integral_constant< int(*)int, &myIntToIntFunction> for instance – user3770392 Jun 07 '17 at 15:18
1

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

AndyG
  • 39,700
  • 8
  • 109
  • 143