【问题标题】:Call less constrained functionally equivalent function调用较少约束的功能等效函数
【发布时间】:2020-04-12 18:47:40
【问题描述】:

考虑以下代码:

#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&lt;HasParent T&gt;(T*)调用通用的foo&lt;T&gt;(T*)函数?

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

【问题讨论】:

  • 所以你想调用通用版本并将T* 传递给HasParent T 版本?
  • 你能做的就是把foo写成template&lt;class T, bool F=false&gt; int foo(T*) { return 1; },然后你可以写foo&lt;T,false&gt;(t),但我希望这不是解决这个问题的唯一方法。
  • @t.niese,这绝对不是唯一的方法,因为总是有相对干净的选择将公共部分分解为单独的函数。
  • @chris 确定这是一种解决从专业调用通用函数的要求的方法(并且可能是更好的方法),但它不会回答问题,如果/如何是有可能的。
  • @chris 除了公共部分是整个其他函数外,重载只是用户以递归方式与父级调用相同的方法,如果可用

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


【解决方案1】:

是否可以从foo&lt;HasParent T&gt;(T*)调用通用的foo&lt;T&gt;(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,所以它不是一个可行的候选者,我们得到了不受约束的模板。

在你的例子中,两者都返回int,所以这个特殊的技巧不起作用。但关键是您需要 some 方法来区分这两个模板。

更好的方法可能是:

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 方法更隐蔽)。

【讨论】:

  • 我们应该在这个答案中提到template&lt;class T&gt; int foo(T*) { if constexpr (HasParent&lt;T&gt;) { } else {} } 吗?当我可以摆脱它时,我非常喜欢不超载。
  • @Casey 这实际上是个好主意,因为它实际上也可以解决我的问题 ;-)
  • @Casey 也许吧?认为专注于特定问题会更有趣,我有点喜欢单态模板参数:-)
猜你喜欢
  • 1970-01-01
  • 2018-10-26
  • 1970-01-01
  • 2023-03-05
  • 2019-09-10
  • 2023-03-06
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多