使用尾随返回类型编写方法以根据方法调用进行更改?

时间:2017-10-11 01:05:53

标签: c++ struct types return trailing

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

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

看到struct包含各种类型的数据,我选择使用基于模板化参数的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&lt; char,char_traits&lt; char&gt;,allocator&lt; char&gt;&gt;')到函数返回类型'decltype(toGet)'(又名' INT')`

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

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

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

另外,如果我对这些信息的理解不正确,请告诉我。我对C ++很新,所以我只是在学习这些功能。

1 个答案:

答案 0 :(得分:0)

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

一个简单的解决方案是使用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
}

但是你遇到的问题是并非所有字段都可以转换为返回类型(请求std::string时无法返回int字段等),所以你可以'仅switch上的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>();

但这也不起作用(“自动返回类型的错误扣除”错误)。