【问题标题】:C++14 using auto keyword in a method's definitionC++14 在方法定义中使用 auto 关键字
【发布时间】:2017-02-16 08:25:19
【问题描述】:

我有几个std::unordered_maps。他们都有一个std::string 作为他们的密钥,他们的数据不同。我想从给定地图的键中创建一个 csv 字符串,因为该数据需要通过线路发送到连接的客户端。目前,我对每个单独的地图都有一个方法。我想让这个通用,我想出了以下内容:

std::string myClass::getCollection(auto& myMap) {
    std::vector <std::string> tmpVec;
    for ( auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

我使用 eclipse 使用 gcc 6.1.0 和 -std=c++14 进行编译,它可以编译但没有链接。 链接器抱怨对std::__cxx11::getCollection(someMap);的未定义引用

无论地图数据和我如何称呼它,它总是告诉我:

Invalid arguments ' Candidates are: std::__cxx11::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt;&gt; getCollection() '

我该如何解决这个问题?

【问题讨论】:

  • std::string myClass::getCollection(auto&amp; myMap) 不是有效的语法。具体来说,auto 不是成员函数的有效参数类型。
  • "我认为在 c++14 中可以使用 auto 作为参数..." 仅适用于 lambdas。 “那么我试图用另一种方法来完成吗?”是的,只需使用普通模板:template&lt;typename MapT&gt; std::string myClass::getCollection(MapT&amp; myMap)
  • 在函数参数中使用 auto 目前是非标准的,但可能会进入 C++20 中的语言。它被称为“缩写函数模板”,我认为它是概念提案的一部分。 GCC 目前将其作为扩展提供;如果你用-pedantic 编译它会失败。
  • 因为'auto'参数就像一个模板参数,你应该在头文件中定义(不仅仅是声明)成员函数 - 否则定义不会在某些翻译单元中被实例化。
  • 缺少minimal reproducible example 链接错误...

标签: c++ parameters c++14 auto


【解决方案1】:

在 C++14 中,auto 参数只允许在 lambda 中使用(根据 @ildjarn 的评论),您可以开发一个 函数模板,在地图类型上进行模板化,例如:

#include <sstream>
#include <string>
#include <vector>

class myClass {
...

template <typename MapType>
std::string getCollection(const MapType& myMap) {
    std::vector <std::string> tmpVec;
    for ( const auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( const auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

还要注意添加const 以获得一些const-正确性。

此外,为什么不直接使用字符串流对象构建输出字符串,而不填充 中间体 vector&lt;string&gt;(代码更多,潜在的错误更多,开销更大,效率更低) ?

而且,由于您只是对使用字符串流作为 输出 流感兴趣,因此使用 ostringstream 而不是 stringstream 会更好,因为它更有效并且可以更好地传达您的意图。

#include <sstream>  // for std::ostringstream
#include <string>   // for std::string
...

template <typename MapType>
std::string getCollection(const MapType& myMap) {
    std::ostringstream ss;
    for (const auto& elem : myMap) {
        ss << elem.first << ',';
    }
    std::string result = ss.str();
    result.pop_back(); // remove the last ','
    return result;
}

【讨论】:

  • 感谢您的改进。我一直有同样的链接问题...未定义的引用`std::__cxx11::
  • 您是否在某些标头中内联实现了模板方法,或者至少可以由您的客户代码访问?您是否包含所有必需的标题(例如&lt;sstream&gt;&lt;vector&gt;&lt;string&gt;,您的地图集合的标题)?
  • 是的,我有模板 std::string getCollection(MapType& myMap);在我的头文件中,该文件包含在模板/函数所在的 cpp 中,并且还包含在调用类方法的另一个头文件中
  • @ZoOl007:如果要在另一个头文件或 .cpp 文件中调用函数模板,则必须在头文件中实现内联。它不像普通的非模板函数,你可以在头文件中声明并在单独的 .cpp 文件中实现。
  • 好的,它现在可以工作了……这对我来说是新的……那么,所有模板化的函数最好完全放在头文件中吗?令人困惑的区别。非常感谢您的宝贵时间!
【解决方案2】:

为什么不直接使用模板?

template <typename TMap>
std::string myClass::GetCollection(TMap &myMap) {
    std::vector <std::string> tmpVec;
    for ( auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

你的方法一模一样,只是我们使用模板函数语法来处理类型推断,而不是auto关键字。

【讨论】:

  • 也许提到auto不能用作函数的参数类型?
  • 谢谢。我仍然对 `std::__cxx11:: 有相同的未定义引用
  • @ZoOl007 :这是一个命名空间,所以你必须在结尾处留下一些东西。在这种情况下的重要部分... ;-]
【解决方案3】:

auto 参数在 C++14 中为 only allowed in lambdas

这可能是因为在像您这样的经典函数中,您可以声明一个函数模板(这基本上是 lambda 案例中发生的情况),而 lambdas 不能是模板。

【讨论】:

    猜你喜欢
    • 2011-03-26
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 2011-04-16
    • 2013-07-15
    • 1970-01-01
    相关资源
    最近更新 更多