变量模板+ std :: map的通用Lambda [英] Variable templates + generic lambdas for std::map

查看:82
本文介绍了变量模板+ std :: map的通用Lambda的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 14变量模板的答案:目的是什么?有用法示例吗?提出了一个变量模板+通用lambda的用法示例,该示例看起来像这样:

An answer to C++14 Variable Templates: what is the purpose? Any usage example? proposes a usage example of variable templates + generic lambdas that would look something like this:

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. 
}

不幸的是它没有编译,所以我试图修复它

Unfortunately it doesn't compile so I've tried to "fix" it and this is my attempt so far.

#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 不会推导每种类型,但最初只能推导一种(双精度)。因此,该代码无效。即使此可能有效,每个存储实例都将引用一个不同的变量。

When you instantiate a variable template, like all templates, each variable will be a different type. The theory is auto doesn't get deduced for each type, but only one type initially (double). Therefore the code is invalid. Even if this could work, each instantiation of storage would refer to a different variable.

如何重写此代码以实现原始意图?

How can this code be rewritten to achieve the original intent?

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

Edit I made a small mistake in my edit (see revision history to avoid wall of text.) decltype(pair) should be decltype(pair.second) since there is only one template argument for 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>'


的未定义引用

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

In order to fix the linker errors, I think you need to explicitly instantiate the arguments? (I'm not even sure if that's the correct term here.)

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

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

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

实时示例

推荐答案

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

这是一个声明,就像 template< typename T>类foo; 。无论如何我们都需要一个定义,我们也会从中受益:

This is a declaration, much like e.g. template<typename T> class foo;. As we need one anyway, we would benefit from making it a definition as well:

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

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

This doesn’t get rid of the linker errors however, suggesting there’s an outstanding bug with implicit instantiation. To convince ourselves, we can trigger instantiation in various ways:


  • 明确地表示,就像

  • explicitly, which would look like

// 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();
    


  • 这两种情况都会驯服链接器。

    in either case taming the linker.

    您尝试的是显式专业化,尽管使用了不同的机制,但确实可以解决该问题。

    What you attempted is explicit specialization, which does indeed get around the issue although using a different mechanism.

    这篇关于变量模板+ std :: map的通用Lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆