首页 > 解决方案 > 不受约束的 requires-expression 参数

问题描述

我可以在 C++20 约束中使用受约束的泛型类型作为概念吗?例如,假设我想编写一个要求,即候选类T有一个函数,该函数func可以接受满足以下条件的任何类型的参数std::ranges::range

template<typename T>
concept Foo = requires (T t, std::ranges:range s) {
    { t.func(a); } -> std::convertible_to<double>;
}

但是 GCC 给了我一条错误消息,即不能在我放置的地方使用占位符类型std::ranges::range

标签: c++c++20c++-concepts

解决方案


在我看来,您正在寻找一个带有(仅声明的)operator T ()泛型的结构T

struct generic_argument
 {
   template <typename T>
   operator T () const;
 };

decltype()所以你可以为每个预期的参数和模板参数传递它(在 a 内)。

所以你的概念(对不起......我将它简化为删除范围参数)变成(如果我理解你想要什么)作为

template<typename T>
concept Foo 
   = std::convertible_to<decltype(std::declval<T>().func(std::declval<generic_argument>())),
                         double>;

下面是一个完整的编译示例

#include <iostream>

struct A { double func (int a) { return a; } };
struct B { double not_func (long a) { return a; } };
struct C { std::string func (char) { return "abc"; } };
struct D { float func (auto) { return 1.0f; } };

struct E { double func (int a) { return a; }
           std::string func (char) { return "abc"; } };

struct generic_argument
 {
   template <typename T>
   operator T () const;
 };

template<typename T>
concept Foo 
   = std::convertible_to<decltype(std::declval<T>().func(std::declval<generic_argument>())),
                         double>;

template <Foo T>
void bar (T const &)
 { std::cout << "bar, Foo version\n"; }

template <typename T>
void bar (T const &)
 { std::cout << "bar, generic version\n"; }

int main()
 {
   bar(A{}); // print bar, Foo version
   bar(B{}); // print bar, generic version [no func() function]
   bar(C{}); // print bar, generic version [no convertible to double]
   bar(D{}); // print bar, Foo version
   bar(E{}); // print bar, generic version [two func() function]
 }

我对E此案表示怀疑:两种func()方法,一种仅返回可转换为的类型double,从bar(E{})我们得到“bar,通用版本”。


推荐阅读