1

I am trying to create a template that will accept a reference to a C-style array of objects as an argument:

#include <iostream>

class A
{
public:
A(){}
};

template<int N, class A& obj> struct W {};

int main()
{
A b[5]; 
W<5,b> w; 
}

But when compile the code I get error:

$ c++ -std=c++11 -g try37.cpp
try37.cpp: In function 'int main()':
try37.cpp:14:5: error: the value of 'b' is not usable in a constant expression
 W<5,b> w;
     ^
try37.cpp:13:3: note: 'b' was not declared 'constexpr'
 A b[5];
   ^
try37.cpp:14:6: error: could not convert template argument 'b' to 'A&'
 W<5,b> w;
      ^
try37.cpp:14:9: error: invalid type in declaration before ';' token
 W<5,b> w;
         ^

I tried many ways but was unable to fix the compilation issue? How to resolve the same?

4
  • 1
    What about simply using std::array instead of raw arrays? Also note that template parameters refer to specify types, rather than objects. Commented Oct 6, 2018 at 18:28
  • I tried but it gives the same error. Can you please provide an example? Commented Oct 6, 2018 at 18:31
  • It does not resolves the compilation issue Commented Oct 6, 2018 at 18:34
  • 1
    Maybe you can tell us what you are trying to achieve (this seems to me to be an XY Problem), I don't think you need that kind of template Commented Oct 6, 2018 at 18:49

4 Answers 4

2

There are some problems in your code.

(1) if you want to pass a reference to an object as template parameter, you have to define it as constexpr and give it external static linkage (static is not necessary, correction from birdfreeyahoo (thanks!)), so

constexpr A b[5]; 

int main ()
 {
   W<5,b> w; 
 }

(2) if you want a (C-style array of) constexpr A object(s) initialized with default constructor, you have to make contexpr the constructor too.

So

public:
constexpr A(){}

(3) if you want that the second template parameter for W is a reference to a constant C-style array of As, where the dimension is the first parameter, the syntax is

template <int N, A const (& obj)[N]>
struct W
 { };

So the full program become

class A
 {
   public:
      constexpr A ()
       { }
};

template <int N, A const (& obj)[N]>
struct W
 { };

constexpr A b[5]; 

int main ()
 {
   W<5, b> w; 
 }
Sign up to request clarification or add additional context in comments.

1 Comment

The global variable doesn't need to be static, since that only determines the linkage type, the storage duration is static even without the keyword
0

Edit : C style array is added to the answer.

if you trying to get struct W to have a container of objects you can use the vectors but. I'm still not sure why you want to do that.

struct W
{
    template<typename Type, typename A> //constructor with a vector
    W(std::vector<Type,A> & vec)
    {
       //...
    }

    template<typename Type>
    W(int arraySize, Type & obj) //constructor with an array
    {
       //...

    }
};

int main()
{
    const int ArraySize = 5;
    A b[ArraySize];
    std::vector<A> vec;

    for(int i =0; i < 5; i++)
        vec.push_back(b[i]);

    W w(vec); //calling struct W constructor that takes a vector.
    W w2(ArraySize,b); //calling struct W constructor that takes c style array
    return 0;
}

12 Comments

My requirement is that I need to create the template with a specific number of instances of class A
im still not sure why you want the template. you already know what you want to pass to W. its a class A type. are you trying to use Template to determine the size of the array you passing to the W? if so thats not the purpose of template arguments.
Class A is just used for an example - it can be just any other class
ah... i see that makes a huge difference
Thanks I think that would resolve the issue my side I can check the vector size - actually I am writing code for a module ensuring that a specific number of instances of an object needs to be passed.
|
0

First of all, you will only be able to pass 1 instance of A to the template. Change it to A[n] obj Note: It will get converted to a pointer to A!

Second, the array you pass has to have static storage duration. So either make the array static or put it as global variable.

3 Comments

Thanks - but how can I make it to accept a non-global variable?
Make it static, but then it acts like a global variable which just can be accessed locally (but it stays the same each function call).
If you want to have a real local variable, you simply can't, because the pointer needs to be a constexpr, and this it can only be if the address is known at compile-time (so static storage duration). This is how templates work.
0
template < typename TElement, std::size_t NElement>
constexpr std::size_t sizeof_array( TElement const (&arr)[NElement] )
{
     (void)arr; // Unused, could have been anonymous
     return NElement;
}

template < typename TArray>
constexpr std::size_t sizeof_array2( const TArray& arr )
{
     return ( sizeof( arr ) / sizeof( arr[0] ) );
}

then in your code:

char arr[] = "abcdef;
sizeof_array(arr); // C-styled array
sizeof_array2(arr);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.