【问题标题】:Why does passing lambda to constrained type template parameter result in `incomplete type` compiler error?为什么将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误?
【发布时间】:2022-01-24 02:30:00
【问题描述】:

我有一个概念可以帮助我检测函数的签名:

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
}

你可以自己试试:

GCC:https://godbolt.org/z/fG6c7E3qf

Clang:https://godbolt.org/z/7G7T8nTde

我认为testWorkstestFails 都应该做同样的事情。我哪里错了?

【问题讨论】:

    标签: c++ templates lambda constraints c++20


    【解决方案1】:

    这两个:

    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) { }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多