返回具有不同模板参数值的不同类型(但类型相同)

陈浩南*_*陈浩南 10 c++ templates return-type template-specialization

我想要做的是定义如下3个函数:

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;
}
Run Code Online (Sandbox Code Playgroud)

它们使用相同类型的模板参数,但返回不同类型。

我相信一定有某种方法可以做到这一点(就像这样 std::get<>()做),但是我找不到如何做到这一点。

Sto*_*ica 13

在我看来,您喜欢功能模板的专业化。需要为每个调用提供不同的实现方式很合适。然而,有一个警告,那就是专门化可能不会改变被专门化的主模板的签名,只会改变实现。这意味着我们不能做例如

template<int t> int test(); // Primary
template<> int test<0>() { return 8; } // OK, signature matches
template<> float test<1>() { return 8.8; } // ERROR
Run Code Online (Sandbox Code Playgroud)

但是我们还没有敬酒。专业化的签名必须与主要参数针对特定参数所获得的签名相匹配。因此,如果使返回类型依赖于template参数,并解析为正确的类型,则可以很好地定义我们的专业化。

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"; }
Run Code Online (Sandbox Code Playgroud)

是否存在类似的东西?是的,您暗示了这一点。我们可以使用std::tuple。它有一个std::tuple_element实用程序,可以将整数映射到类型序列之一(元组的元素)。有了一点帮助,我们就可以构建代码以按您希望的方式工作:

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"; }
Run Code Online (Sandbox Code Playgroud)

现在,每个专业化名称都匹配主要的签名。因此,我们得到了编译器的认可。

现场观看


JeJ*_*eJo 7

@StoryTeller@ formerlyknownas_463035818提供了一个良好的解释这样做的模板专业化道路。或者,可以使用if-constexprdecltype(auto)返回,将这三个函数组合为一个函数。

#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;
}
Run Code Online (Sandbox Code Playgroud)

请参见在线直播


for*_*818 5

您实际上声明了3次相同的模板,而实际上却想进行专业化。据我所知,您不能直接研究返回类型(*)。但是,没有任何其他间接层无法解决的问题。您可以执行以下操作:

#include <string>

template <int> struct return_type_tag {};
template <> struct return_type_tag<0> { using type = int; };
template <> struct return_type_tag<1> { using type = float; };
template <> struct return_type_tag<2> { using type = std::string; };

template <int x> typename return_type_tag<x>::type test();

template<> int test<0>() { return 8; }
template<> float test<1>() { return 8.8; }
template<> std::string test<2>() { return "8.9"; }

int main()
{
    int a = test<0>();
    float b = test<1>();
    std::string c = test<2>();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(*)实际上,您可以通过一点技巧来查看此答案。我的方法的唯一好处是,它已经在c ++ 11之前运行。