从模板函数返回多个值为std :: tuple

时间:2017-01-13 23:14:47

标签: c++ templates

试图让这段代码起作用,但是想要找出解决方案。我知道我不能在返回类型上重载,但不知道如何解决它。

我收到此错误,但不确定它从何处获取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;
}

3 个答案:

答案 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;
}