【发布时间】:2020-12-08 17:30:53
【问题描述】:
我正在尝试实现一个函数模板ovl,这样ovl<Foo, Bar>(f) 将返回f 的重载,采用(Foo, Bar),并且对我的幼稚解决方案所发生的事情感到非常惊讶:
template <class... Args, class Ret>
constexpr auto ovl(Ret (*const f)(std::type_identity_t<Args>...)) { return f; }
void foo();
void foo(int);
void foo(int, int);
int main() {
ovl<int>(foo)(0);
}
prog.cc:26:5: fatal error: no matching function for call to 'ovl'
ovl<int>(foo)(0);
^~~~~~~~
prog.cc:6:16: note: candidate template ignored: couldn't infer template argument 'Ret'
constexpr auto ovl(Ret (*const f)(std::type_identity_t<Args>...)) { return f; }
^
GCC 和 Clang 也会出现同样的错误。更重要的是,它在我自己枚举可能的arities时确实有效:
template <class Ret>
constexpr auto ovl(Ret (*const f)()) { return f; }
template <class Arg0, class Ret>
constexpr auto ovl(Ret (*const f)(std::type_identity_t<Arg0>)) { return f; }
template <class Arg0, class Arg1, class Ret>
constexpr auto ovl(Ret (*const f)(std::type_identity_t<Arg0>, std::type_identity_t<Arg1>)) { return f; }
// ... ad nauseam.
有趣的是,保留 Args... 但硬编码返回类型也可以:
template <class... Args>
constexpr auto ovl(void (*const f)(std::type_identity_t<Args>...)) { return f; }
似乎在将部分显式参数提供给参数包时会忽略它们,但为什么呢?以及如何确保在尝试消除函数指针歧义时考虑它们?
注意:我发现了以下解决方法,它先烘焙 Args...,然后再推断 Ret,但我仍然对答案感兴趣,因为这很笨重。
template <class... Args>
struct ovl_t {
template <class Ret>
constexpr auto operator()(Ret (*const f)(Args...)) const { return f; }
};
template <class... Args>
constexpr ovl_t<Args...> ovl;
【问题讨论】:
-
我怀疑这里的正确答案可能会进入语言律师领域。用language-lawyer 标记这个问题可能有助于注意
-
你能详细说明一下笨重吗?也许还有其他一些解决方法。
-
@StoryTeller-UnslanderMonica 恐怕如果不是重复的,至少是相同的原因......该死。
-
@PasserBy my complete use cas 为成员函数(
const,非const,合格)和可变参数提供了额外的重载和变体,并为每个函数生成了一个完整的类模板和变量模板案例感觉有点笨拙,如果有效 - 特别是因为我觉得我离一个基于功能的工作实现有点怪癖。
标签: c++ templates overloading variadic-templates template-argument-deduction