Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing array element to template

I think code below is self explanatory. I can easily pass static variable to template parameter and it work as expected. Using static array will cleanup code, so it look nicer, but unfortunately it doesn't compile due to error I pasted in comment. Note that it was compiled by gcc 10.2 with c++17 flag. So the question is how to pass array element to template.

#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;
}  
like image 415
docp Avatar asked Oct 28 '20 12:10

docp


People also ask

How to pass array in c++ by reference?

Arrays can be passed by reference OR by degrading to a pointer. For example, using char arr[1]; foo(char arr[]). , arr degrades to a pointer; while using char arr[1]; foo(char (&arr)[1]) , arr is passed as a reference. It's notable that the former form is often regarded as ill-formed since the dimension is lost.

Can you pass array to function c++?

C++ does not allow to pass an entire array as an argument to a function. However, You can pass a pointer to an array by specifying the array's name without an index.

How to pass array to function pointer?

A whole array cannot be passed as an argument to a function in C++. You can, however, pass a pointer to an array without an index by specifying the array's name. In C, when we pass an array to a function say fun(), it is always treated as a pointer by fun().

Are arrays always passed by reference in C?

Arrays are always pass by reference in C. Any change made to the parameter containing the array will change the value of the original array. The ampersand used in the function prototype. To make a normal parameter into a pass by reference parameter, we use the "& param" notation.


2 Answers

TL;DR upgrade your compiler, and hope that they fully implement C++20.


The problem is purely one about non-type template parameters

template<int&>
struct S;

static int i;
static int arr[42];

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

The static is also irrelevant, in case you're wondering.

This rule exist in C++17 [temp.arg.nontype]

For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject, [...]

Which got relaxed in C++20

For a non-type template-parameter of reference or pointer type, [...] the reference or pointer value shall not refer to or be the address of (respectively):

  • a temporary object,
  • a string literal object,
  • the result of a typeid expression,
  • a predefined __func__ variable, or
  • a subobject of one of the above.

As to why, I can only postulate that the standard cautiously only required a very small subset of values to avoid the possibility that it isn't implementable.

like image 184
Passer By Avatar answered Oct 22 '22 09:10

Passer By


There were an answer here (which was deleted) that gave me an idea how to solve it. It's not perfect, but also not bad.

#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;
}  
like image 31
docp Avatar answered Oct 22 '22 08:10

docp