C++ Concepts:requires子句为何未检测构造函数内部约束?
C++ Concepts中requires子句的判断矛盾问题探究
问题背景
通过最小可复现示例(MWE)探究C++ Concept里requires子句的特殊现象,目标是实现一个判断函数类型能否被指定参数调用的concept(尽管std::invocable可实现该功能,此处仅作演示)。
定义的concept如下:
template <typename func_t, typename... args_t> concept callable = requires(const func_t& f, const args_t&... args) {f(args...);};
按预期,只要调用操作合法(包含隐式类型转换),该concept应返回true。例如用接受const double&的lambda测试时,callable<decltype(func), int>和callable<decltype(func), double>均为true,符合预期。
自定义类型测试与矛盾现象
首先定义一组自定义类型:
enum space {space1,space2}; template <const space sp> struct type2_t{}; template <const space sp> struct type1_t { type1_t(){} template <const space sp_r> type1_t(const type2_t<sp_r>& t2){} };
此时type2_t可任意转换为type1_t,对应的三个callable判断均为true,符合预期。若在type1_t的构造函数上添加requires (sp_r == sp)约束,callable<decltype(func), type2_t<space2>>会变为false,也符合预期。
但当移除构造函数的requires约束,转而在构造函数内部调用的dummy_func上添加该约束时:
template <const space sp> struct type1_t { type1_t(){} template <const space sp_r> requires (sp_r == sp) void dummy_func(const type2_t<sp_r>& t2){} template <const space sp_r> type1_t(const type2_t<sp_r>& t2) { dummy_func(t2); } };
预期callable<decltype(func), type2_t<space2>>应为false,但实际结果为true。然而直接调用func(type2_t<space2>())会编译失败,这与concept的判断结果产生矛盾。
核心疑问
- 该矛盾的根源是什么?
- 为何编译器未完全检查concept的requires子句内代码的有效性?
附录
- 已知应使用
std::invocable,此处仅作演示,且std::invocable存在同样问题。 - 将约束放在
type1_t构造函数上可解决问题,但这在项目中不可行。
完整测试代码
#include <iostream> #include <concepts> enum space { space1, space2 }; template <typename func_t, typename... args_t> concept callable = requires(const func_t& f, const args_t&... args) {f(args...);}; template <const space sp> struct type2_t{}; template <const space sp> struct type1_t { type1_t(){} template <const space sp_r> requires (sp_r == sp) void dummy_func(const type2_t<sp_r>& t2){} template <const space sp_r> type1_t(const type2_t<sp_r>& t2) { dummy_func(t2); } }; int main(int argc, char** argv) { auto func = [](const type1_t<space1>& t1) -> int {return 1;}; std::cout << callable<decltype(func), type1_t<space1>> << std::endl; //true std::cout << callable<decltype(func), type2_t<space1>> << std::endl; //true std::cout << callable<decltype(func), type2_t<space2>> << std::endl; //true, should be false!! }
注:使用g++ 11.3,编译参数-std=c++20。
内容的提问来源于stack exchange,提问作者wvn
相关产品推荐
相关产品推荐

