调用约束较少的功能等效函数

Call less constrained functionally equivalent function

考虑以下代码:

#include <iostream>
#include <type_traits>

struct A;

template<class T>
concept HasParent = std::is_convertible_v<typename T::parent*, A*>;

struct A{};

struct B : A { using parent = A; };

template<class T>       int foo(T*) { return 1; }

template<HasParent T>   int foo(T*)
{
  // call the other one?
  return 2;
}

int main()
{
  B b;
  std::cout << foo(&b) << std::endl; // displays 2
  return 0;
}

是否可以从 foo<HasParent T>(T*) 调用通用 foo<T>(T*) 函数?

(这是一个(功能)示例,但我可以 link github 上的完整代码)

Is it possible to call the general foo<T>(T*) function from foo<HasParent T>(T*)?

您需要一些方法来区分这两个函数才能做到这一点。

例如:

template <typename T>               void foo(T);
template <typename T> requires true auto foo(T) -> int;

对于所有T,第二个显然比第一个更受约束,所以foo(42)调用第二个。但是,您可以区分两者:

auto unconstrained = static_cast<void(*)(int)>(foo);

在这里,约束函数模板 returns int 所以它不是一个可行的候选者,我们改为使用不受约束的模板。

在你的例子中,return int,所以这个特殊的技巧不起作用。但关键是你需要一些的方式来区分这两个模板。

更好的方法可能是:

template <typename T, std::monostate M = {}>
void foo(T);

template <typename T> requires true
void foo(T arg) {
    foo<T, std::monostate{}>(arg); // calls the unconstrained one
}

在这里使用 monostate 有点可爱,因为它实际上并没有改变模板实例化的数量(只有一个 monostate... )。 foo(42) 调用第二个,调用第一个。 Demo.

但最好只添加一个新函数,并让函数模板的不受约束和受约束版本都调用该函数模板(从某种意义上说,它可以说比 monostate 方法更隐蔽)。