【问题标题】:Use decltype to get the type of function return while the function is being defined在定义函数时使用 decltype 获取函数返回的类型
【发布时间】:2020-11-30 18:34:49
【问题描述】:

我正在尝试制作一个带有数字的“元组生成器”,并且 返回具有此数字的元组,同时它的每个元素都递增 一个。当然我知道这不是元组的真正应用, 但我想尝试它来学习新东西。这是我所拥有的:

template<int N>
auto getTupleN(int start){
    return std::tuple_cat(std::tuple<int>(start), getTupleN<N-1>(start+1));
}

template<>
auto getTupleN<0>(int start){
    return std::make_tuple(start);
}

现在,它运行良好,我可以使用 std::get 访问元组的元素。 但是,我无法推断出类型。

我想用箭头符号写一个函数来确保函数 返回我希望它返回的内容,并且我很好地掌握了模板的概念。 这是我想要的(当然,由于各种原因,它不起作用):

template<int N>
//    error: ‘getTupleN’ was not declared in this scope
auto getTupleN(int start) -> decltype(std::tuple_cat(std::tuple<int>, getTupleN<N-1>)){
    return std::tuple_cat(std::tuple<int>(start), getTupleN<N-1>(start+1));
}

template<>
//     error: expected initializer before ‘<’ token
auto getTupleN<0>(int start) -> std::tuple<int>{
    return std::make_tuple(start);
}

我认为现在应该可以理解我的问题是什么了 - 我怎样才能重写这个定义以便它使用箭头符号,所以我确定它返回我想要的?

编辑。 所以我使用了第一个答案的想法,我得到的错误是:

error: ‘getTupleN’ was not declared in this scope
auto getTupleN(int start) -> decltype(std::tuple_cat(std::tuple<int>(start), getTupleN<N-1>(start+1))){

error: expected initializer before ‘<’ token
auto getTupleN<0>(int start) -> std::tuple<int>{

【问题讨论】:

  • 当它不是“当然”时,请不要说“当然”。最好在问题中包含错误消息
  • @idclev463035818 好的,我已经编辑了问题
  • 您添加的是对答案的回应,这也许应该是对该答案的评论。我要求包括您的代码错误。您当前有一些没有错误消息的代码和没有相应代码的错误消息。有点混乱
  • @idclev463035818 错误信息下方显示对应代码
  • 该错误消息下面的行是不完整的代码。

标签: c++ templates variadic-templates variadic-functions


【解决方案1】:

简单地说,你不能这样做。这是鸡和蛋。

[basic.scope.pdecl]

1 名称的声明点紧跟其后 完整的声明符([dcl.decl])和它的初始化器(如果有的话)之前, 除非下面注明。

如果没有尾随返回类型,函数(模板)的声明符是不完整的。就声明而言,在您指定尾随返回类型之前,没有声明 getTupleN 之类的东西(因此您不能使用它来声明返回类型)。即使一般规则下的段落包含例外,也没有例外可以使您的代码格式良好。

【讨论】:

  • 就良好实践而言,如果我需要确定返回类型,是否应该避免使用此类函数?我知道这是一种罕见的情况,但对我来说很奇怪,编译器可以解决某些问题,而我却无法解决。
  • @KarolSzustakowski - 不,这不是一个坏习惯。对通用函数进行返回类型推导的动机之一是它简化了某些用例,例如您所拥有的用例。它不是灵丹妙药(可能会损害 SFINAE 的友好性,因此您有时可能不想使用它),但如果它符合您的需求,就可以应用。
  • @KarolSzustakowski:“我需要确定返回类型”。不确定auto f() -&gt; decltype(ret) { return ret; }auto f() { return ret; } 更“确定”。
【解决方案2】:

语法应该是:

decltype(std::tuple_cat(std::tuple<int>(start), getTupleN<N-1>(start+1)))

但问题是返回类型取决于自身(以及最终的特化)。

如果你想提供返回类型,你可能需要创建辅助特征:

template <std::size_t I, typename T>
using type_t = T;

template <typename Seq> struct int_tuple_impl;

template <std::size_t ... Is>
struct int_tuple_impl<std::index_sequence<Is...>>
{
    using type = std::tuple<type_t<Is, int>...>;  
};

template <std::size_t N>
using int_tuple = typename int_tuple_impl<std::make_index_sequence<N>>::type;

所以

emplate<int N>
auto getTupleN(int start) -> int_tuple<N + 1>
{
    return std::tuple_cat(std::tuple<int>(start), getTupleN<N-1>(start+1));
}

template<>
auto getTupleN<0>(int start) -> int_tuple<1> // or directly std::tuple<int>
{
    return std::make_tuple(start);
}

【讨论】:

  • 我想过这个,但是使用decltype的时候没有声明getTupleN
  • fwiw,我想这是 OP 正在努力解决的实际问题 godbolt.org/z/1vq8vc
【解决方案3】:

你不需要指定返回类型:

#include <tuple>
#include <utility>
#include <cstdlib>
#include <iostream>

template<size_t ... Is>
auto getTupleN(size_t start, std::index_sequence<Is...>) {
    return std::make_tuple((start + Is)...);
}

template<size_t N>
auto getTuple() {
    return getTupleN(N, std::make_index_sequence<N>());
}

int main() {
    auto res = getTuple<3>();
    // prints 3 4 5
    std::cout << std::get<0>(res) << ' ' <<
        std::get<1>(res) << ' ' << std::get<2>(res) << std::endl;
}

【讨论】:

    猜你喜欢
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 2018-11-06
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多