【问题标题】:Write method with trailing return type to change based on method call?编写带有尾随返回类型的方法以根据方法调用进行更改?
【发布时间】:2018-03-22 12:52:16
【问题描述】:

我有一个名为 Eclipse 的类,它有一个私有结构成员,其中包含大约 30 个不同数据类型的字段。

我有一个方法可以根据作为参数传入的字段编号从结构中返回数据字段。

鉴于该结构包含各种类型的数据,我选择使用auto 关键字和基于模板化参数的尾随返回类型。我的方法头在下面。

template<typename TheType>
auto getColumnData(TheType toGet, int fieldNum) -> decltype(toGet) {
    // switch statement to return fields based on fieldNum
}

如果我想返回 int 的列,我调用 getColumnData(0, 1);。第一个参数仅用于确定方法的返回类型,第二个参数确定返回给方法调用者的字段号。

理论上,这将导致getColumnData() 的返回类型为int 并返回结构的第一列(对应于第一个字段)。但是我收到了这个编译错误:

没有从返回值类型“std::string”(又名“basic_string, allocator”)到函数返回类型“decltype(toGet)”(又名“int”)的可行转换')`

我了解,如果我以int 作为第一个参数调用此方法,并使用与返回std::string 的字段相对应的字段编号,则会出现问题。但是,根据其他类的检查,这种情况永远不会发生。

有什么方法可以强制我的编译器接受此代码,即使它在某些情况下可能不正确?

我知道我可以重载该方法,但如果我能弄清楚如何只用一个来完成任务,我宁愿不要有多个不同的方法用于基本相同的目的。

另外,如果我对这些信息的任何理解似乎不正确,请告诉我。我对 C++ 很陌生,所以我只是边学习边学习这些特性。

【问题讨论】:

  • 这是完全错误的。如果第一个参数是int,则decltype 指定函数根据定义返回int。句号。故事结局。从那时起,您写的其他所有内容都无关紧要。实例化的模板函数必须返回一个 int,没有 ifs、ands 或 buts。

标签: c++ struct types return trailing


【解决方案1】:

您不能像您尝试做的那样在运行时动态更改方法的返回类型。您的第一个参数不是编译时已知的数据类型。它只是一个在运行时填充的整数,因此您根本无法根据它做出编译时决策。

一个简单的解决方案是使用std::variant(C++17 或更高版本)或boost::variant(C++11 及更高版本)作为返回类型:

using FieldType = std:::variant<int, std::string>;

FieldType getColumnData(int fieldNum) {
    // switch statement to return fields based on fieldNum
}

int i = std::get<int>(getColumnData(1));
std::string s = std::get<std::string>(getColumnData(2));

否则,您必须将返回类型设为模板参数,而不是方法参数:

template<typename TheType>
TheType getColumnData(int fieldNum) {
    // switch statement to return fields based on fieldNum
}

但是你遇到的问题是并非所有字段都可以转换为返回类型(当请求 int 时,不能返回 std::string 字段等),所以你不能只是 @987654330 @ 在fieldNum 上,因为它不在编译时进行评估。

您可能想将字段编号设为模板参数,使其在编译时保持不变,然后对其进行专门化处理:

template<const int FieldNum>
auto getColumnData() { return 0; };

template<> int getColumnData<1>() { return private_struct.Field1; }
template<> std::string getColumnData<2>() { return private_struct.Field2; }
// etc...

int i = getColumnData<1>();
std::string s = getColumnData<2>();

但是当我尝试在模板化的类方法上执行此操作时(“非命名空间范围内的显式特化”)会出错。

你可能很想做这样的事情,并希望编译器优化掉未使用的分支:

template<const int FieldNum>
auto getColumnData() {
    if (FieldNum == 1) return private_struct.Field1;
    if (FieldNum == 2) return private_struct.Field2;
    //etc...
    return 0;
}

template<const int FieldNum>
auto getColumnData()
{
    switch (FieldNum) {
        case 1: return private_struct.Field1;
        case 2: return private_struct.Field2;
        // etc...
    }
    return 0;
};

int i = getColumnData<1>();
std::string s = getColumnData<2>();

但这也不起作用(“自动返回类型的推断不一致”错误)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-09
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    相关资源
    最近更新 更多