C++20依赖模板Concept编译失败求助:关联约束不满足
问题核心原因与解决方案
错误根源
你的Listener是双模板参数的concept(T表示调用者类型,V表示Update的内部类型),但在listen函数的约束写法Listener<UpdateV> auto&&中,仅传递了一个模板参数UpdateV,完全不符合Listener的参数要求:
- 编译器会误认为你要将
Listener的第一个模板参数T绑定为UpdateV类型,但你的Lambda显然不是UpdateV,自然判定约束不满足; - 同时,
Listener的第二个参数V没有被指定,编译器也无法自动推导,最终触发“关联约束不满足”的错误。
修正方案
方案1:明确指定concept的两个模板参数
修改listen函数的约束写法,直接用requires子句明确指定Listener的两个参数:Lambda的类型,以及MySignal的模板参数V。
完整代码:
#include <vector> #include <functional> #include <iostream> #include <concepts> template <typename V> struct Update { V val; }; template <typename T, typename V> concept Listener = requires(T t, Update<V> update) { { t(update) } -> std::convertible_to<void>; }; template <typename V> struct MySignal { using UpdateV = Update<V>; using Func = std::function<void(UpdateV)>; // 明确指定Listener的两个模板参数:lambda类型和V void listen(auto&& listener) requires Listener<decltype(listener), V> { listeners_.emplace_back(Func{ listener }); } std::vector<Func> listeners_; }; int main(int argc, char** argv) { MySignal<int64_t> sig; sig.listen([](Update<int64_t> u) { std::cout << "Got a signal\n"; }); }
方案2:调整concept为单参数适配场景
如果希望保留Listener<UpdateV> auto&&的写法,可以将Listener改为接受目标Update类型的单参数concept:
#include <vector> #include <functional> #include <iostream> #include <concepts> template <typename V> struct Update { V val; }; // 改为接受调用者类型T和目标Update类型U的concept template <typename T, typename U> concept Listener = requires(T t, U update) { { t(update) } -> std::convertible_to<void>; }; template <typename V> struct MySignal { using UpdateV = Update<V>; using Func = std::function<void(UpdateV)>; // 此时Listener<UpdateV>会自动推导T为lambda类型,U为UpdateV void listen(Listener<UpdateV> auto&& listener) { listeners_.emplace_back(Func{ listener }); } std::vector<Func> listeners_; }; int main(int argc, char** argv) { MySignal<int64_t> sig; sig.listen([](Update<int64_t> u) { std::cout << "Got a signal\n"; }); }
补充说明
你之前疑惑为什么requires子句里能写Update<V>但编译器不认可——这是因为requires子句里的Update<V>依赖于concept的第二个模板参数V,但当你在listen里只传一个参数给Listener时,这个V根本没有被绑定或推导,编译器无法确定Update<V>具体是什么类型,自然没法完成约束检查。
内容的提问来源于stack exchange,提问作者AdrianH
相关产品推荐
相关产品推荐

