首页 > 解决方案 > 调用较少约束的功能等效函数

问题描述

考虑以下代码:

#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<T>(T*)函数foo<HasParent T>(T*)

(这是一个(功能性)示例,但我可以在 github 上链接完整代码)

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

解决方案


是否可以从 调用通用foo<T>(T*)函数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);

在这里,受约束的函数模板返回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)调用第二个,后者调用第一个。演示

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


推荐阅读