引用类型和 odr 使用的模板非类型参数
Template non-type arguments for reference type and odr-used
下面示例代码中的变量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
从未定义,但如果提供 -g
选项,clang 会拒绝它作为链接错误。
比照。 http://melpon.org/wandbox/permlink/nF45k7un3rFb175z
上面的示例代码是 Boost ML 代码的简化版本,clang 也拒绝它。
比照。 http://melpon.org/wandbox/permlink/ZwxaygXgUhbi1Cbr
我认为(但我不确定)引用类型的模板非类型参数是 odr-used 即使它们没有在模板主体中引用所以 Boost ML 的模式格式错误。
我的理解正确吗?
我相信 v
是 odr-used。 f<v>
是一个 template-id (14.2) 其 template-argument 是一个 id-expression (5.1.1) - 一种表达形式。它显然不是未求值的操作数(它没有作为 typeid
、sizeof
、noexcept
或 decltype
的操作数出现),因此它是 可能求值的 根据 3.2/2:
3.2/2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof...
此时,我们有
3.2/3 A variable x
whose name appears as a potentially-evaluated expression ex
is odr-used unless [a condition that doesn't appear to apply here as no lvalue-to-rvalue conversion is applied].
[basic.def.odr]/3:
A variable x
whose name appears as a potentially-evaluated expression
ex
is odr-used by ex
unless applying the lvalue-to-rvalue conversion
(4.1) to x
yields a constant expression (5.19) [..]
不幸的是,此时将 l-t-r 转换应用于 v
不会产生常量表达式 - [expr.const]/2:
A conditional-expression e
is a core constant expression unless
the evaluation of e
, following the rules of the abstract machine
(1.9), would evaluate one of the following expressions: [..]
— an
lvalue-to-rvalue conversion (4.1) unless it is applied to
a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding
initialization, initialized with a constant expression [..], or
a non-volatile glvalue that refers to a non-volatile object defined with constexpr
, or that refers
to a non-mutable sub-object of such an object, or
- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
e
;
然而,尽管 Matt 建议的实现方式不正确,但这个想法肯定是正确的。 中演示了一种使用此方法的简单方法,即使用辅助模板。在你的情况下,试试
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.
下面示例代码中的变量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
从未定义,但如果提供 -g
选项,clang 会拒绝它作为链接错误。
比照。 http://melpon.org/wandbox/permlink/nF45k7un3rFb175z
上面的示例代码是 Boost ML 代码的简化版本,clang 也拒绝它。
比照。 http://melpon.org/wandbox/permlink/ZwxaygXgUhbi1Cbr
我认为(但我不确定)引用类型的模板非类型参数是 odr-used 即使它们没有在模板主体中引用所以 Boost ML 的模式格式错误。
我的理解正确吗?
我相信 v
是 odr-used。 f<v>
是一个 template-id (14.2) 其 template-argument 是一个 id-expression (5.1.1) - 一种表达形式。它显然不是未求值的操作数(它没有作为 typeid
、sizeof
、noexcept
或 decltype
的操作数出现),因此它是 可能求值的 根据 3.2/2:
3.2/2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof...
此时,我们有
3.2/3 A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used unless [a condition that doesn't appear to apply here as no lvalue-to-rvalue conversion is applied].
[basic.def.odr]/3:
A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.19) [..]
不幸的是,此时将 l-t-r 转换应用于 v
不会产生常量表达式 - [expr.const]/2:
A conditional-expression
e
is a core constant expression unless the evaluation ofe
, following the rules of the abstract machine (1.9), would evaluate one of the following expressions: [..]— an lvalue-to-rvalue conversion (4.1) unless it is applied to
a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression [..], or
a non-volatile glvalue that refers to a non-volatile object defined with
constexpr
, or that refers to a non-mutable sub-object of such an object, or- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
e
;
然而,尽管 Matt 建议的实现方式不正确,但这个想法肯定是正确的。
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.