如果 constexpr 格式正确,是否在内部使用了 static_assert?
Is this use of static_assert inside if constexpr well-formed?
我昨天读了一些 ,关于在 if constexpr
的 else
子句中使用 static_assert(false, "Some message")
。我知道根据标准,它被认为是格式错误(即使某些编译器(包括 MSVC2017)会接受它)。 Qt 也会将此标记为错误。
我的问题是,下面的代码格式正确是否符合标准? (我倾向于这么认为,但我想确认一下。)
template <typename TypeOfValue>
static void PushValue(duk_context* ctx, TypeOfValue value) {
// Push value onto duktape stack
if constexpr (std::is_same<TypeOfValue, int>::value) {
// Push int
duk_push_int(ctx, value);
} else if constexpr (std::is_same<TypeOfValue, uint32_t>::value) {
// Push uint
duk_push_uint(ctx, value);
} else {
// Unsupported type
static_assert(bool_value<false, TypeOfValue>(), "Unsupported type");
}
}
template <bool value, typename T>
static constexpr bool bool_value() {return value;}
编辑:
从我收到的评论来看,bool_value 似乎应该这样定义:
template<bool value, typename T>
struct bool_value {
static constexpr bool value = value;
};
使用模式
// Unsupported type
static_assert(bool_value<false, TypeOfValue>::value, "Unsupported type");
它是合式的,只是因为 bool_value 可以专门化为 returns true 用于表达式 bool_value<false, TypeOfValue>::value
。
of the question you linked explains why it's ill-formed. Note the quote from the Standard temp.res-8,上面写着(强调我的)
The validity of a template may be checked prior to any instantiation. [...] The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or...
[...]
Otherwise, no diagnostic shall be issued for a template for which a valid specialization can be generated.
[ Note: If a template is instantiated, errors will be diagnosed according to the other rules in this document.
Exactly when these errors are diagnosed is a quality of implementation issue.
— end note
]
在关于 if
的 cppreference page 中,您可以看到以下解决方法(强调我的)
The common workaround for such a catch-all statement is a type-dependent expression that is always false:
template<class T> struct dependent_false : std::false_type {};
template <typename T>
void f() {
if constexpr (std::is_arithmetic_v<T>)
// ...
else
static_assert(dependent_false<T>::value, "Must be arithmetic"); // ok
}
中所述
theoretically, this is still ill-formed, because [...] is always false
unless you actually have a specialization that returns true.
因此您可以将该专业化添加到之前的代码片段中
namespace {
// Do not unleash.
struct aggressive_unicorn_type;
}
template<> struct dependent_false<aggressive_unicorn_type> : std::true_type {};
这是否有必要完全满足标准文档,这取决于对 的解释能否 生成 .
我想知道这是否真的很重要。 OP 询问代码是否格式正确,但他们实际上是在尝试生成格式错误的代码,并在某些条件下进行诊断(这就是 static_assert(false)
所暗示的,参见 dcl.pre) .
正如提问者已经指出的那样,当传递“错误”类型的参数时,还有其他方法可以强制编译器出错(考虑即将到来的标准的概念),也许,如果我们想使用 static_assert
s 与 if constexpr
结合使用时,最好的选择可能是依赖于类型的表达式,即 not 始终为 false。
#include <type_traits>
void f(int) {};
void g(unsigned) {};
template< class T>
constexpr inline bool is_supported =
std::is_same_v<T, int> ||
std::is_same_v<T, unsigned> ||
std::is_same_v<T, char>;
template <class T>
void use(T value) {
static_assert(is_supported<T>, "Not supported");
if constexpr (std::is_same<T, int>::value) {
f(value);
} else if constexpr (std::is_same_v<T, unsigned>){
g(value);
} else {
static_assert( !is_supported<T>, "Not yet implemented");
}
}
我将添加我自己的最终想法作为答案,因为我似乎没有从其他来源获得足够原则性的答案。
我在阅读了几个 other 答案后得出的结论是:
根据标准,允许编译器提前评估static_assert(false, "...")
。如果是,它会生成一个永远无法编译的程序。
无法编译的程序格式错误。
因此,问题是允许编译器尽早评估 static_assert,即使在 if constexpr
.
中也是如此
通过引入人为依赖模板参数的 false
强制它延迟评估直到实例化时间,对我来说似乎有点做作。但我承认还有其他考虑因素可能使其成为正确的语言选择。 (这就是我希望专家回答能够阐明的那种事情。)
您的两次尝试(使用函数和结构)都是格式正确的。
mentions [temp.res]/8
,但我不同意它的解释方式。
The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or ...
您编写的函数和结构 可以 专门化为 true
。我相信仅仅有专业化的可能性就足够了,您实际上不需要添加虚拟 true
专业化来使代码格式正确。
根据我的理解(我希望是根据常识),标准这部分的要点是允许编译器尽早检查模板和 if constexpr
分支的有效性(当它们出现时第一次),拒绝无法实例化的。
模板中的每个分支 都可以 可能被实例化,因为 bool_value()
可以 稍后被专门化。我怀疑一个理智的编译器会拒绝你的代码,因为 bool_value()
没有被专门化 yet.
我昨天读了一些 if constexpr
的 else
子句中使用 static_assert(false, "Some message")
。我知道根据标准,它被认为是格式错误(即使某些编译器(包括 MSVC2017)会接受它)。 Qt 也会将此标记为错误。
我的问题是,下面的代码格式正确是否符合标准? (我倾向于这么认为,但我想确认一下。)
template <typename TypeOfValue>
static void PushValue(duk_context* ctx, TypeOfValue value) {
// Push value onto duktape stack
if constexpr (std::is_same<TypeOfValue, int>::value) {
// Push int
duk_push_int(ctx, value);
} else if constexpr (std::is_same<TypeOfValue, uint32_t>::value) {
// Push uint
duk_push_uint(ctx, value);
} else {
// Unsupported type
static_assert(bool_value<false, TypeOfValue>(), "Unsupported type");
}
}
template <bool value, typename T>
static constexpr bool bool_value() {return value;}
编辑:
从我收到的评论来看,bool_value 似乎应该这样定义:
template<bool value, typename T>
struct bool_value {
static constexpr bool value = value;
};
使用模式
// Unsupported type
static_assert(bool_value<false, TypeOfValue>::value, "Unsupported type");
它是合式的,只是因为 bool_value 可以专门化为 returns true 用于表达式 bool_value<false, TypeOfValue>::value
。
The validity of a template may be checked prior to any instantiation. [...] The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or...
[...]
Otherwise, no diagnostic shall be issued for a template for which a valid specialization can be generated. [ Note: If a template is instantiated, errors will be diagnosed according to the other rules in this document. Exactly when these errors are diagnosed is a quality of implementation issue. — end note ]
在关于 if
的 cppreference page 中,您可以看到以下解决方法(强调我的)
中所述The common workaround for such a catch-all statement is a type-dependent expression that is always false:
template<class T> struct dependent_false : std::false_type {}; template <typename T> void f() { if constexpr (std::is_arithmetic_v<T>) // ... else static_assert(dependent_false<T>::value, "Must be arithmetic"); // ok }
theoretically, this is still ill-formed, because [...] is always
false
unless you actually have a specialization that returns true.
因此您可以将该专业化添加到之前的代码片段中
namespace { // Do not unleash. struct aggressive_unicorn_type; } template<> struct dependent_false<aggressive_unicorn_type> : std::true_type {};
这是否有必要完全满足标准文档,这取决于对 的解释能否 生成 .
我想知道这是否真的很重要。 OP 询问代码是否格式正确,但他们实际上是在尝试生成格式错误的代码,并在某些条件下进行诊断(这就是 static_assert(false)
所暗示的,参见 dcl.pre) .
正如提问者已经指出的那样,当传递“错误”类型的参数时,还有其他方法可以强制编译器出错(考虑即将到来的标准的概念),也许,如果我们想使用 static_assert
s 与 if constexpr
结合使用时,最好的选择可能是依赖于类型的表达式,即 not 始终为 false。
#include <type_traits> void f(int) {}; void g(unsigned) {}; template< class T> constexpr inline bool is_supported = std::is_same_v<T, int> || std::is_same_v<T, unsigned> || std::is_same_v<T, char>; template <class T> void use(T value) { static_assert(is_supported<T>, "Not supported"); if constexpr (std::is_same<T, int>::value) { f(value); } else if constexpr (std::is_same_v<T, unsigned>){ g(value); } else { static_assert( !is_supported<T>, "Not yet implemented"); } }
我将添加我自己的最终想法作为答案,因为我似乎没有从其他来源获得足够原则性的答案。
我在阅读了几个 other 答案后得出的结论是:
根据标准,允许编译器提前评估
static_assert(false, "...")
。如果是,它会生成一个永远无法编译的程序。无法编译的程序格式错误。
因此,问题是允许编译器尽早评估 static_assert,即使在 if constexpr
.
通过引入人为依赖模板参数的 false
强制它延迟评估直到实例化时间,对我来说似乎有点做作。但我承认还有其他考虑因素可能使其成为正确的语言选择。 (这就是我希望专家回答能够阐明的那种事情。)
您的两次尝试(使用函数和结构)都是格式正确的。
[temp.res]/8
,但我不同意它的解释方式。
The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or ...
您编写的函数和结构 可以 专门化为 true
。我相信仅仅有专业化的可能性就足够了,您实际上不需要添加虚拟 true
专业化来使代码格式正确。
根据我的理解(我希望是根据常识),标准这部分的要点是允许编译器尽早检查模板和 if constexpr
分支的有效性(当它们出现时第一次),拒绝无法实例化的。
模板中的每个分支 都可以 可能被实例化,因为 bool_value()
可以 稍后被专门化。我怀疑一个理智的编译器会拒绝你的代码,因为 bool_value()
没有被专门化 yet.