引用类型和odr使用的模板非类型参数

时间:2015-03-30 12:55:18

标签: c++ boost language-lawyer

示例代码中的变量v odr-used

extern void* v;

template<void*&>
void f() {}

int main()
{
    f<v>();
}

我在Boost ML中找到了这种模式。

比照http://lists.boost.org/Archives/boost/2011/04/180082.php

它表示从未定义boost::enabler,但 clang 会在提供-g选项时将其拒绝为链接错误。

比照http://melpon.org/wandbox/permlink/nF45k7un3rFb175z

上面的示例代码是Boost ML代码的缩减版本,而 clang 也拒绝它。

比照http://melpon.org/wandbox/permlink/ZwxaygXgUhbi1Cbr

我认为(但我不确定)参考类型的模板非类型参数是 odr-used ,即使它们未在模板体中引用,因此Boost ML&#39; s模式是不正确的。

我的理解是否正确?

2 个答案:

答案 0 :(得分:7)

我相信v odr-used f<v> template-id 14.2 ), template-argument id-expression 5.1.1 ) - 一种表达形式。它显然不是未评估的操作数(它不会显示为typeidsizeofnoexceptdecltype的操作数,因此它&# 39; s 可能评估 3.2 / 2

  

3.2 / 2 表达式可能被评估,除非它是未评估的操作数(第5条)或其子表达式......

此时,我们有

  

3.2 / 3 变量x的名称显示为潜在评估的表达式ex odr-used 除非[条件似乎没有在此处应用,因为没有应用左值到右值的转换]。

答案 1 :(得分:2)

[basic.def.odr] / 3:

  

变量x,其名称显示为可能已评估的表达式   除非应用左值到右值转换,否则ex ex odr-used   (4.1)到x产生一个常量表达式(5.19) [..]

不幸的是,此时将l-t-r转换应用于v不会产生常量表达式 - [expr.const] / 2:

  

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

     

- 一个   左值 - 右值转换(4.1),除非它适用于

     
      
  • 整数或枚举类型的非易失性glvalue,它引用具有前一个的非易失性const对象   初始化,使用常量表达式[..]或

  • 初始化   
  • 非易失性glvalue ,指的是使用constexpr 定义的非易失性对象,或者引用          到这种对象的不可变子对象,或

  •   
  • 文字类型的非易失性glvalue,引用一个非易失性对象,其生命周期始于e 的评估范围内;
  •   

然而,虽然Matt建议的实施并不正确,但这个想法当然是。使用帮助器模板在this answer中演示了使用此方法的简单方法。在您的情况下,请尝试

template <bool cond, int id=0>
using distinct_enable_if =
    typename std::enable_if<cond, std::integral_constant<int,id>*>::type;

class test
{
public:
  template< class... T,
            distinct_enable_if<sizeof...(T) == 10> = nullptr> 
  test( T&&... ) {}

  template< class T,
            distinct_enable_if<std::is_arithmetic<T>{}> = nullptr>
  operator T() const { return T{}; }

  /* Note the additional template argument:
     It ensures that the template parameter lists are not identical, 
     and the ODR isn't violated */
  template< class T,
            distinct_enable_if<std::is_pointer<T>{}, 1> = nullptr>
  operator T() const { return T{}; }
};

Demo