【问题标题】:Passing array element to template将数组元素传递给模板
【发布时间】:2021-02-10 19:41:56
【问题描述】:

我认为下面的代码是不言自明的。我可以轻松地将静态变量传递给模板参数,它可以按预期工作。使用静态数组将清理代码,因此看起来更好,但不幸的是,由于我在评论中粘贴的错误,它无法编译。请注意,它是由带有 c++17 标志的 gcc 10.2 编译的。 所以问题是如何将数组元素传递给模板。

#include <iostream>
#include <vector>
#include <tuple>

using DataTransfer = std::tuple<char, int>;
using DataPool     = std::vector<DataTransfer>;

typedef struct Event
{
    DataPool dataPool;
    const char* description;
} Event;

template <Event& event>
class EventTransmitter
{
    public:
    EventTransmitter()
    {
        std::cout<<event.description<<"\n";
    }
};

static Event ev1{ {{'d', 4}, {'a', 1}}, "Description 1"};
static Event ev2{ {{'g', 7}, {'b', 6}}, "Description 2"};

static Event evs[2] {
    { {{'d', 4}, {'a', 1}}, "Description 1"},
    { {{'g', 7}, {'b', 6}}, "Description 2"}
};

int main()
{
    EventTransmitter<ev1> e1;
    EventTransmitter<ev2> e2;
    
    //EventTransmitter<evs[0]> e3;
    //error: '& evs[0]' is not a valid template argument of
    //type 'Event&' because 'evs[0]' is not a variable
    return 0;
}  

【问题讨论】:

  • 为什么要从模板中为每个对象创建一个新类?我不知道这是可能的。为什么不直接将对象传递给构造函数?你甚至不需要模板。始终以最不令人惊讶的方式编写程序,您的代码非常令人惊讶。
  • gcc (trunk) 使用-std=c++20 编译代码并给出预期的输出,但不是-std=c++17。 clang 可能给出了更好的错误信息:non-type template argument refers to subobject 'evs[0]'godbolt.org/z/6exajh
  • @mch 假设您的文档需要只能处理特定事件的事件处理程序。将错误的处理程序绑定到错误的事件时,每个处理程序都有不同的类型允许编译错误。这只是您想要使用此类代码的一种可能性。
  • @mch 这只是非常简化的代码,因此它可读。实际上,还有很多事情迫使我像上面的代码那样做。

标签: c++ arrays templates c++17


【解决方案1】:

TL;DR 升级你的编译器,希望他们完全实现 C++20。


问题纯粹是关于非类型模板参数的问题

template<int&>
struct S;

static int i;
static int arr[42];

S<i> s1;
S<arr[0]> s2;  // ill-formed?

static 也无关紧要,如果您想知道的话。

这条规则存在于 C++17 [temp.arg.nontype]

对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应是地址):

  • 一个子对象,[...]

C++20放松了

对于引用或指针类型的非类型模板参数,[...] 引用或指针值不应引用或作为(分别)的地址:

  • 一个临时对象,
  • 一个字符串字面量对象,
  • typeid 表达式的结果,
  • 预定义的 __func__ 变量,或
  • 上述之一的子对象。

至于为什么,我只能假设标准谨慎地只需要非常小的值子集,以避免它无法实现的可能性。

【讨论】:

  • 避免这样的模板参数有两个原因:需要破坏通过对象到其子对象的“路径”,以及对模板参数的== 含义的一些长期混淆。实施者认为第一个没什么大不了的,委员会gradually recovered from the latter
【解决方案2】:

这里有一个答案(已删除),让我知道如何解决它。它并不完美,但也不错。

#include <iostream>
#include <vector>
#include <tuple>

using DataTransfer = std::tuple<char, int>;
using DataPool     = std::vector<DataTransfer>;

typedef struct Event
{
    DataPool dataPool;
    const char* description;
} Event;

template <Event* event, int index>
class EventTransmitter
{
    public:
    EventTransmitter()
    {
        std::cout<<(event+index)->description<<"\n";
    }
};

static Event ev1{ {{'d', 4}, {'a', 1}}, "Description 1"};
static Event ev2{ {{'g', 7}, {'b', 6}}, "Description 2"};

static Event evs[2] {
    { {{'d', 4}, {'a', 1}}, "Description 1"},
    { {{'g', 7}, {'b', 6}}, "Description 2"}
};

int main()
{
    //EventTransmitter<&ev1> e1;
    //EventTransmitter<&ev2> e2;
    
    EventTransmitter<evs, 0> e3;
    EventTransmitter<evs, 1> e4;

    return 0;
}  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 2018-08-29
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    相关资源
    最近更新 更多