非类型模板参数:如何传递对基类对象的引用?

时间:2016-05-11 14:04:50

标签: c++

似乎无法传递引用 派生对象的基类对象作为模板参数, 我试着在这里做:

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;
//   ^

我原本期望'c'对象'default_a',因为它来自 'a',可以接受为'const a&amp;',就像它在第16行。

为什么这不能作为模板参数?

规范的哪一部分实际上要求这种行为?

也许我的gcc-5.3.0版本有些缺陷?

有人找到了一个很好的解决方法/将派生对象作为基类对象引用模板参数传递的方法吗?

我不能仅仅将引用变量'c_as_a'替换为'default_a' 模板参数列表:

template < const a & The_A = c_as_a >

t.C:24:7:错误:'const a&amp; c_as_a'不是类型'const a&amp;'的有效模板参数因为引用变量没有常量地址      b将&GT; A_B;

我也无法替换任何constexpr函数调用,它会执行以下操作:

 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 ) >

因为此调用不是“具有外部链接的对象”。

任何建议如何实现如何实现将派生对象的基类的引用作为模板参数传递 - 非常感谢 - 这是 得到可能,我只是看不到ATM。

必须有一种方法可以将对象的基类对象的引用指定为模板参数。

3 个答案:

答案 0 :(得分:1)

gcc特定的解决方法:

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;

以上编译确定。

令人高兴的是,我们知道'_default_c'的名称并未受损。

答案 1 :(得分:0)

问题是初始化const引用时会创建临时值,并且在此上下文中不允许使用引用初始化(转换后的常量表达式)。

N4140 8.5.3(5.2.2.1)

  

...

     
      
  • 如果T1是非类型类型,则为临时类型&#34; cv1 T1&#34;从初始化表达式创建并复制初始化(8.5)。   然后将引用绑定到临时。
  •   
     

除了最后一个之外的所有情况(即创建和初始化a   暂时从初始化表达式),引用据说   直接绑定到初始化表达式。

然后在5.19:

  

条件表达式 e核心常量表达式,除非   e的评估,遵循抽象机器的规则   (1.9),将评估以下表达式之一:

     

(2.9)    - 一个 id-expression ,它引用引用类型的变量或数据成员,除非引用具有先前的初始化并且   任

     
      
  • 用常量表达式初始化或......
  •   

答案 2 :(得分:0)

修复它在名称空间中的作用:

namespace U {
    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 "C" {
    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;
}