What I want to do is to define 3 functions like these:
template<int t = 0> int test() { return 8; }
template<int t = 1> float test() { return 8.8; }
template<int t = 2> std::string test() { return "8.9"; }
int main()
{
int a = test<0>();
float b = test<1>();
std::string c = test<2>();
return 0;
}
They use the same type of template parameter but return different types.
I believe there must be some way to do that (like std::get<>()
does it), but I can not find how to do it.
It looks to me like you are after function template specialization. Needing to provide a different implementation for each of the calls fits the bill. There is however one caveat, and it's that a specialization may not alter the signature of the primary template being specialized, only the implementation. This means we cannot do e.g.
template<int t> int test(); // Primary
template<> int test<0>() { return 8; } // OK, signature matches
template<> float test<1>() { return 8.8; } // ERROR
But we are not toasted yet. The signature of the specialization has to match the one that primary will get for a specific argument. So if we make the return type dependent on the template parameter, and resolve to the correct type, we could define our specialization just fine.
template<int t> auto test() -> /* Magic involving t that resolves to int, float, string */;
template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }
Does something like that exist? Yes, and you hinted at it. We can use std::tuple
. It has a std::tuple_element
utility that can map an integer to one of a type sequence (the tuple's elements). With a little helper, we can construct our code to work the way you wish:
using types = std::tuple<int, float, std::string>;
template<int t> auto test() -> std::tuple_element_t<t, types>;
template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }
Now every specialization matches the signature the primary would end up with. And so we get an approval from our compiler.
See it live
The @StoryTeller and @formerlyknownas_463035818 have provided a well-explained template specialization way of doing it. Alternatively, one can combine the three functions to one single function using if-constexpr and with a decltype(auto)
return in c++17.
#include <iostream>
#include <string>
#include <cstring>
using namespace std::literals;
template<int t>
constexpr decltype(auto) test() noexcept
{
if constexpr (t == 0) return 8;
else if constexpr (t == 1) return 8.8f;
else if constexpr (t == 2) return "8.9"s;
}
(See live online)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With