为什么将 lambda 传递给约束类型模板参数会导致“不完整类型”编译器错误?
Why does passing lambda to constrained type template parameter result in `incomplete type` compiler error?
我有一个概念可以帮助我检测函数的签名:
template <typename>
struct FuncHelper;
template <typename R, typename... Args>
struct FuncHelper<R(Args...)> {
template <typename Func>
static constexpr bool is_like = requires(const Func& f, Args... args) {
{ f(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
};
template <typename FX, typename T>
concept function_like = FuncHelper<FX>::template is_like<T>;
我可以在函数重载中使用这个概念作为约束:
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
// I can call this like testWorks([&](){ return true; });
但是,如果我在模板参数中指定此约束:
template <function_like<bool()> T>
void testFails(T&& func) { }
// testFails([&](){ return true; }); // Compiler error: incomplete type
然后我收到一个编译器错误,说我的类型不完整。
完整代码如下:
#include <concepts>
#include <type_traits>
#include <utility>
using namespace std;
template <typename>
struct FuncHelper;
template <typename R, typename... Args>
struct FuncHelper<R(Args...)> {
template <typename Func>
static constexpr bool is_like = requires(const Func& f, Args... args) {
{ f(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
};
template <typename FX, typename T>
concept function_like = FuncHelper<FX>::template is_like<T>;
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }
void testAll() {
testWorks([&](){ return true; }); // No errors!
testFails([&](){ return true; }); // Compiler error: incomplete type
}
您可以自己尝试一下:
海湾合作委员会:https://godbolt.org/z/fG6c7E3qf
叮当声:https://godbolt.org/z/7G7T8nTde
我认为 testWorks
和 testFails
应该做同样的事情。我哪里错了?
这两个:
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }
不等价。后者相当于:
template <typename T> requires function_like<T, bool()>
void testFails(T&& func) { }
注意function_like
中参数的不同顺序。
问题是您的概念不是为正确处理类型约束语法而构建的。您需要翻转参数:
template <typename T, typename Sig>
concept function_like = FuncHelper<Sig>::template is_like<T>;
然后这两个都可以正常工作(因为现在它们实际上是等价的):
template <typename T> requires function_like<T, bool()>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }
我有一个概念可以帮助我检测函数的签名:
template <typename>
struct FuncHelper;
template <typename R, typename... Args>
struct FuncHelper<R(Args...)> {
template <typename Func>
static constexpr bool is_like = requires(const Func& f, Args... args) {
{ f(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
};
template <typename FX, typename T>
concept function_like = FuncHelper<FX>::template is_like<T>;
我可以在函数重载中使用这个概念作为约束:
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
// I can call this like testWorks([&](){ return true; });
但是,如果我在模板参数中指定此约束:
template <function_like<bool()> T>
void testFails(T&& func) { }
// testFails([&](){ return true; }); // Compiler error: incomplete type
然后我收到一个编译器错误,说我的类型不完整。
完整代码如下:
#include <concepts>
#include <type_traits>
#include <utility>
using namespace std;
template <typename>
struct FuncHelper;
template <typename R, typename... Args>
struct FuncHelper<R(Args...)> {
template <typename Func>
static constexpr bool is_like = requires(const Func& f, Args... args) {
{ f(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
};
template <typename FX, typename T>
concept function_like = FuncHelper<FX>::template is_like<T>;
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }
void testAll() {
testWorks([&](){ return true; }); // No errors!
testFails([&](){ return true; }); // Compiler error: incomplete type
}
您可以自己尝试一下:
海湾合作委员会:https://godbolt.org/z/fG6c7E3qf
叮当声:https://godbolt.org/z/7G7T8nTde
我认为 testWorks
和 testFails
应该做同样的事情。我哪里错了?
这两个:
template <typename T> requires function_like<bool(), T>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }
不等价。后者相当于:
template <typename T> requires function_like<T, bool()>
void testFails(T&& func) { }
注意function_like
中参数的不同顺序。
问题是您的概念不是为正确处理类型约束语法而构建的。您需要翻转参数:
template <typename T, typename Sig>
concept function_like = FuncHelper<Sig>::template is_like<T>;
然后这两个都可以正常工作(因为现在它们实际上是等价的):
template <typename T> requires function_like<T, bool()>
void testWorks(T&& func) { }
template <function_like<bool()> T>
void testFails(T&& func) { }