为何含constexpr-if与std::is_copy_assignable的C++代码无法编译?
为什么这段带constexpr-if的代码无法编译?
这段代码中,static_assert已经验证Foo不可拷贝赋值,但constexpr-if块内的代码并未被编译器丢弃,从而引发了调用已删除函数的错误。
代码示例
#include <type_traits> struct Foo { Foo() = default; Foo const& operator=(Foo const&) = delete; }; int main() { static_assert(!std::is_copy_assignable_v<Foo>); Foo x; Foo other; if constexpr (std::is_copy_assignable_v<Foo>) { other = x; } return 0; }
编译错误信息
<source>: In function 'int main()': <source>:16:17: error: use of deleted function 'const Foo& Foo::operator=(const Foo&)' 16 | other = x; | ^ <source>:5:16: note: declared here 5 | Foo const& operator=(Foo const&) = delete; | ^~~~~~ Compiler returned: 1
问题原因与解决方法
问题核心在于非模板上下文下constexpr-if的行为特性:
- 在非模板函数(比如这里的
main)中,即使constexpr-if的条件是常量表达式false,编译器仍会对分支内的代码进行语义检查,而非完全丢弃。 - 虽然
std::is_copy_assignable_v<Foo>确实为false(Foo的拷贝赋值运算符被显式删除,导致other = x表达式非法),但非模板上下文里的false分支代码依然会被编译器检查语义,调用已删除函数自然触发错误。
解决方法是将逻辑迁移到模板函数中:模板上下文里,当constexpr-if的条件是不依赖模板参数的常量false时,分支内的代码会被完全丢弃,不会进行语义检查。示例代码如下:
#include <type_traits> struct Foo { Foo() = default; Foo const& operator=(Foo const&) = delete; }; template<typename T> void assign_if_possible(T& dest, const T& src) { if constexpr (std::is_copy_assignable_v<T>) { dest = src; } } int main() { static_assert(!std::is_copy_assignable_v<Foo>); Foo x; Foo other; assign_if_possible(other, x); return 0; }
内容的提问来源于stack exchange,提问作者joergbrech
相关产品推荐
相关产品推荐

