Reputation: 141
Trying to get this code to work, but strugling to figure out a solution. I know that I cannot overload on the return type, but not sure how to solve it then.
I'm getting this error, but not sure where it gets a std::basic_string non reference from? error C2440: 'return': cannot convert from 'std::tuple<std::basic_string<char,std::char_traits<char>,std::allocator<char>>,int &,float &>' to 'std::tuple<std::string &,int &,float &>'
#include <functional>
#include <iostream>
#include <string>
#include <tuple>
template <typename T>
T Get();
template <>
std::string Get() { return std::string{ "Hello" }; }
template <>
int Get(){ return 42; }
template <>
float Get() { return 42.0; }
template <typename T>
std::tuple<T> Generate()
{
return std::make_tuple(Get<T>());
}
template <typename T1, typename... Ts>
std::tuple<T1,Ts...> Generate()
{
auto t = std::make_tuple(Get<T1>());
return std::tuple_cat(t, Generate<Ts...>());
}
struct A
{
template <typename... Ts >
operator std::tuple<Ts...> ()
{
return Generate<Ts...>();
}
};
int main()
{
std::string s;
int i;
float f;
A as;
std::tie(s, i, f) = as;
}
Upvotes: 1
Views: 1568
Reputation: 141
Adding my own answer as I had a second issue that I failed to include in the original question. I needed indexes passed to the Get function so used this indices building trick that I found in a different post.
#include <functional>
#include <iostream>
#include <string>
#include <tuple>
template <std::size_t... Is>
struct Indices {};
template <std::size_t N, std::size_t... Is>
struct IndicesBuilder : IndicesBuilder<N - 1, N - 1, Is...>
{};
template <std::size_t... Is>
struct IndicesBuilder<0, Is...>
{
using type = Indices<Is...>;
};
template <typename T>
T& Get(int index);
template <>
std::string& Get<std::string&>(int index) { std::cout << index << std::endl; static std::string s{ "Hello" }; return s; }
template <>
int& Get<int&>(int index) { std::cout << index << std::endl; static int i{ 42 }; return i; }
template <>
float& Get<float&>(int index) { std::cout << index << std::endl; static float f{ 42 }; return f; }
template <typename... Ts, std::size_t... N>
std::tuple<Ts...> Generate(Indices<N...>)
{
return std::tie(Get<Ts>(N)...);
}
struct A
{
template <typename... Ts >
operator std::tuple<Ts...> ()
{
constexpr std::size_t count = sizeof...(Ts);
return Generate<Ts...>(typename IndicesBuilder<count>::type());
}
};
int main()
{
std::string s;
int i;
float f;
A as;
std::tie(s, i, f) = as;
std::cout << s << " " << i << " " << f << std::endl;
}
Upvotes: 0
Reputation: 66932
std::tie(s, i, f) = as;
The left side is tuple<string&,int&,float&>
, so the right hand side will try to convert to the same thing. Note those references. So for this to work, Generate
will have to return matching types. So make_tuple
has to go, that will have to be tie
. But your Get
functions also need to return references. Can do. While I was at it, I simplified the Generate call to not be recursive.
template <typename T>
T Get();
//note references, and a static variable, and explicitly saying T
template <>
std::string& Get<std::string&>() { static std::string a{ "Hello" }; return a;}
template <>
int& Get<int&>(){ static int a{42}; return a; }
template <>
float& Get<float&>() { static float a{42.0f}; return a; }
// note tie and non-recursive
template <typename ...T>
std::tuple<T...> Generate()
{
return std::tie(Get<T>()...);
}
struct A
{
template <typename... Ts >
operator std::tuple<Ts...> ()
{
return Generate<Ts...>();
}
};
int main()
{
std::string s;
int i;
float f;
A as;
std::tie(s, i, f) = as;
std::cout << "pass";
}
Proof of execution: http://coliru.stacked-crooked.com/a/036817509172da69
As SU3 notes, Generate
is redundant. Could have been
struct A
{
template <typename... Ts >
operator std::tuple<Ts...> ()
{
return std::tie(Get<T>()...);
}
};
Upvotes: 1
Reputation: 5399
How about this?
#include <iostream>
#include <string>
#include <tuple>
template <typename T>
T Get();
template <>
std::string Get<std::string>() { return "Hello"; }
template <>
int Get<int>(){ return 42; }
template <>
float Get<float>() { return 42.0; }
template <typename... Args>
std::tuple<Args...> Generate() {
return { Get<Args>()... };
}
int main()
{
std::string s;
int i;
float f;
std::tie(s, i, f) = Generate<std::string,int,float>();
std::cout << s << std::endl;
std::cout << i << std::endl;
std::cout << f << std::endl;
}
You can't specialize the function templates by just specifying the return type. Instead, you need to explicitly provide the template parameter.
Also, your use of std::tuple
implies that you are using C++11 or above, so you may use parameter packs instead of recursion. This is just syntactic sugar, but it lets you write just one Generate()
function implementation.
Upvotes: 0