Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

non-type template parameter : how to pass reference to base class object?

Tags:

c++

It does not seem to be possible to pass a reference to the base class object of a derived object as a template parameter, as I try to do here:

struct a
{ int _v;
  constexpr a():_v(0){}
  constexpr a(int v): _v(v){} 
};

struct c: public a
{ constexpr c():a(){}
  constexpr c(int v):a(v){} 
};

extern const c default_a;

constexpr const c default_a { 1 };

const a& c_as_a = default_a;
//    ^-- this line (16) causes no error - c can be converted to a

template < const a & The_A = default_a >
struct b
{ constexpr static const a &the_a = The_A;
};

b<> a_b;

// Template instantiation causes error:
// t.C:24:7: error: could not convert template argument 'default_a' to 'const a&'
// b<> a_b;
//   ^

I would have expected the 'c' object 'default_a', since it is derived from 'a', to be acceptable as a 'const a&', as it is on the line 16.

Why isn't this OK as a template parameter ?

What section of specification actually mandates this behaviour ?

Maybe my build of gcc-5.3.0 is somehow defective ?

Anyone found a good workaround / way of passing a derived object as a base class object reference template parameter ?

I cannot just substitute the reference variable 'c_as_a' for 'default_a' in template argument list:

template < const a & The_A = c_as_a >

t.C:24:7: error: 'const a& c_as_a' is not a valid template argument for type 'const a&' because a reference variable does not have a constant address b<> a_b;

Nor can I substitute any constexpr function call which does something like:

 constexpr const a& c_as_a( const c &c ){ return *reinterpret_cast<const a*>(&c);}
 ...
 template < const a & The_A = c_as_a( default_a ) >

since this call is not an 'object with external linkage'.

Any suggestions how to achieve passing a reference to a base class of a derived object as a template parameter would be much appreciated - it's got to be possible, I just can't see how ATM.

There must be a way of specifying a reference to an object's base class object as a template parameter.

like image 942
JVD Avatar asked May 11 '16 14:05

JVD


1 Answers

A gcc specific workaround:

struct a
{ int _v;
  constexpr a():_v(0){}
  constexpr a(int v): _v(v){} 
};

struct c: public a
{ constexpr c():a(){}
  constexpr c(int v):a(v){} 
};

extern const c _default_c;

constexpr const c _default_c { 1 };

extern const a default_a;

const a default_a __attribute__((alias("_default_c")));

template < const a & The_A = default_a >
struct b
{ constexpr static const a &the_a = The_A;
};

b<> a_b;

The above compiles OK .

Happily, we know that the name of '_default_c' is not mangled.

like image 64
JVD Avatar answered Nov 11 '22 10:11

JVD