C++ 概念:无论 return 类型是什么,检查 method/operator 是否存在

C++ concept: check if a method/operator exists no matter what return type is

假设我正在编写一个模板函数,它想在其模板参数上调用 operator+= 并且不关心它是否 return 是新值(T 类型), void 或其他任何内容。例如:

template<class T>
void incrementAll(T *array, int size, T value) {
    for (int i = 0; i < size; ++i) {
        array[i] += value;
    }
}

我想对此函数进行约束:使其需要 T 上的 concept。但是,我找不到对 return 类型没有任何要求的。我能想到的唯一想法是 std::convertible_to<void>(因为我们可以将任何值转换为 void,对吧?),但它失败了:

#include <concepts>

template<class T>
concept Incrementable = requires(T a, T b) {
        {a += b} -> std::convertible_to<void>;
};

template<class T> requires Incrementable<T>
void incrementAll(T *array, int size, T value) {
    for (int i = 0; i < size; ++i) {
        array[i] += value;
    }   
}

int main() {
        int arr[] = {1};
        incrementAll(arr, 1, 1); 
}
nikolay@KoLin:~$ g++ another_tmp.cpp -std=c++20 -fconcepts-diagnostics-depth=10
another_tmp.cpp: In function ‘int main()’:
another_tmp.cpp:17:21: error: no matching function for call to ‘incrementAll(int [1], int, int)’
   17 |         incrementAll(arr, 1, 1);
      |         ~~~~~~~~~~~~^~~~~~~~~~~
another_tmp.cpp:9:6: note: candidate: ‘template<class T>  requires  Incrementable<T> void incrementAll(T*, int, T)’
    9 | void incrementAll(T *array, int size, T value) {
      |      ^~~~~~~~~~~~
another_tmp.cpp:9:6: note:   template argument deduction/substitution failed:
another_tmp.cpp:9:6: note: constraints not satisfied
another_tmp.cpp: In substitution of ‘template<class T>  requires  Incrementable<T> void incrementAll(T*, int, T) [with T = int]’:
another_tmp.cpp:17:14:   required from here
another_tmp.cpp:4:9:   required for the satisfaction of ‘Incrementable<T>’ [with T = int]
another_tmp.cpp:4:25:   in requirements with ‘T a’, ‘T b’ [with T = int]
another_tmp.cpp:5:12: note: ‘a += b’ does not satisfy return-type-requirement, because
    5 |         {a += b} -> std::convertible_to<void>;
      |          ~~^~~~
another_tmp.cpp:5:10: error: deduced expression type does not satisfy placeholder constraints
    5 |         {a += b} -> std::convertible_to<void>;
      |         ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
another_tmp.cpp:5:10: note: constraints not satisfied
In file included from another_tmp.cpp:1:
/usr/include/c++/11.2.0/concepts:72:13:   required for the satisfaction of ‘convertible_to<decltype(auto) [requires std::convertible_to<<placeholder>, void>], void>’ [with decltype(auto) [requires std::convertible_to<<placeholder>, void>] = int&]
/usr/include/c++/11.2.0/concepts:72:30: note: the expression ‘is_convertible_v<_From, _To> [with _From = int&; _To = void]’ evaluated to ‘false’
   72 |     concept convertible_to = is_convertible_v<_From, _To>
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

那么,这里定义的正确概念是什么?

如果您不关心它的 return 类型是什么,那么您可以简单地使用 requires 子句来要求表达式 a += b 为 well-formed :

template<class T>
concept Incrementable = requires(T a, T b) {
  a += b;
};

不过,这样的概念对于可增量类型来说似乎过于宽松,要求return类型像{a += b} -> same_as<T&>一样T&并命名为[=似乎更合适15=] 什么的。