试图让这段代码起作用,但是想要找出解决方案。我知道我不能在返回类型上重载,但不知道如何解决它。
我收到此错误,但不确定它从何处获取std :: basic_string非引用? 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;
}
答案 0 :(得分:1)
std::tie(s, i, f) = as;
左侧是tuple<string&,int&,float&>
,因此右侧将尝试转换为相同的东西。请注意这些参考。因此,要使其正常工作,Generate
必须返回匹配类型。所以必须make_tuple
,必须tie
。但是您的Get
函数也需要返回引用。可以做。当我在它的时候,我将Generate调用简化为不是递归的。
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";
}
执行证明:http://coliru.stacked-crooked.com/a/036817509172da69
正如SU3所说,Generate
是多余的。本来可以
struct A
{
template <typename... Ts >
operator std::tuple<Ts...> ()
{
return std::tie(Get<T>()...);
}
};
答案 1 :(得分:0)
这个怎么样?
#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;
}
您只能通过指定返回类型来专门化功能模板。相反,您需要显式提供模板参数。
此外,使用std::tuple
意味着您使用的是C ++ 11或更高版本,因此您可以使用参数包而不是递归。这只是语法糖,但它只允许你编写一个Generate()
函数实现。
答案 2 :(得分:0)
添加我自己的答案,因为我有第二个问题,我没有在原始问题中包含。我需要传递给Get函数的索引,所以使用了我在不同帖子中找到的这个索引构建技巧。
#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;
}