Reputation: 473
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
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
Upvotes: 1
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);
}
Upvotes: 2
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