【问题标题】:Variable templates + generic lambdas for std::map用于 std::map 的变量模板 + 通用 lambda
【发布时间】:2014-02-06 21:51:13
【问题描述】:

answer to C++14 Variable Templates: what is the purpose? Any usage example? 提出了一个变量模板 + 通用 lambda 的使用示例,如下所示:

void some_func() {
    template<typename T>
    std::map<int, T> storage;

    auto store = []<typename T>(int key, const T& value) { storage<T>.insert(key, value) };

    store(0, 2);
    store(1, "Hello"s);
    store(2, 0.7);

    // All three values are stored in a different map, according to their type. 
}

不幸的是它没有编译,所以我试图“修复”它,这是我迄今为止的尝试。

#include <map>

template<typename T>
std::map<int, T> storage;

void some_func() {

    auto store = [](int key, const auto& value) { storage<decltype(value)>.insert(key, value); };

    store(0, 2);
    store(1, std::string("Hello"));
    store(2, 0.7);
}

错误信息是:

main.cpp:7:76: error: no matching member function for call to 'insert'

    auto store = [](int key, const auto& value) { storage<decltype(value)>.insert(key, value); };
                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
main.cpp:10:10: note: in instantiation of function template specialization 'some_func()::<anonymous class>::operator()<std::basic_string<char> >' requested here

    store(1, std::string("Hello"));

当您实例化一个变量模板时,就像所有模板一样,每个变量都将是不同的类型。理论是auto 不会为每种类型推导出来,但最初只有一种类型(双)。因此代码无效。即使这可以工作,每个存储实例都会引用不同的变量。

如何重写这段代码以达到最初的意图?


编辑我在编辑中犯了一个小错误(请参阅修订历史记录以避免出现文字墙。)decltype(pair) 应该是decltype(pair.second),因为storage 只有一个模板参数。

#include <map>

template <typename T>
std::map<int, T> storage;

void some_func() {
    auto store = [&](auto pair) { storage<decltype(pair.second)>.insert(pair); };

    store(std::pair<int, int>(0, 1));
    store(std::pair<int, std::string>(1, "Hello!"));
    store(std::pair<int, int>(2, 3));
}

int main()
{
}

现在存在链接器错误。

/tmp/main-5f1f7c.o: In function `some_func()':
main.cpp:(.text+0x1a): undefined reference to `storage<int>'
main.cpp:(.text+0x43): undefined reference to `storage<std::string>'
main.cpp:(.text+0x74): undefined reference to `storage<int>'

为了修复链接器错误,我认为您需要显式实例化参数? (我什至不确定这是否是正确的术语。)

template <typename T>
std::map<int, T> storage;

template <>
std::map<int, int> storage<int>;

template <>
std::map<int, std::string> storage<std::string>;

Live Example

【问题讨论】:

  • 你能概括地描述一下最初的意图是什么吗?也就是说,我们尝试使用这样的代码实现的想法是什么?
  • 你也确定你的编译器支持变量模板吗?
  • @PlasmaHH 我正在使用 Coliru,它有 clang 3.5。
  • 我认为问题在于:这不是一个捕获 lambda,所以映射(即使它是一个全局变量)没有被 lambda 捕获。
  • Lambda 签名是对的??? lambda 不应该是:auto store = [&amp;] (decltype(storage)::value_type val) { storage.insert(val); };

标签: c++ c++14


【解决方案1】:
template<typename T>
std::map<int, T> storage;

这是一个声明,很像例如template&lt;typename T&gt; class foo;。因为无论如何我们都需要一个,所以我们也会从定义它中受益:

template<typename T>
std::map<int, T> storage {};

然而,这并没有消除链接器错误,这表明隐式实例化存在一个突出的错误。为了说服自己,我们可以通过多种方式触发实例化:

  • 明确地说,看起来像

    // namespace scope, same as storage
    template /* sic */ std::map<int, int>         storage<int>;
    template           std::map<int, std::string> storage<std::string>;
    
  • 隐式地,通过在main 中添加以下内容

    storage<int>.size();
    storage<std::string>.size();
    

在任何一种情况下都可以驯服链接器。

您尝试的是明确的专业化,尽管使用了不同的机制,但确实解决了这个问题。

【讨论】:

  • 是的,使用 clang++3.5 主干 199418 可以正常工作/失败 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
  • 2018-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
相关资源
最近更新 更多