gpt4 book ai didi

c++ - 使用给定的参数包消除重载函数的歧义

转载 作者:行者123 更新时间:2023-12-03 10:04:39 25 4
gpt4 key购买 nike

我正在尝试实现一个函数模板 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 出现相同的错误。更重要的是,它实际上在自己枚举可能的参数时起作用:

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.
Wandbox demo
有趣的是,保持 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;

最佳答案

我相信这是一个编译器错误。
正如@StoryTeller - Unslander Monica 提到的 [temp.arg.explicit]

Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.


这意味着即使我们提供了 int参数,编译器将尝试为 Args 推导出更多参数.
然而 [temp.deduct.call]

If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.


试用扣除额为
template<typename... Args, typename Ret>
void trial(Ret(*)(std::type_identity_t<Args>...));

trial<int>((void(*)())foo); // fails
trial<int>((void(*)(int))foo); // succeeds
trial<int>((void(*)(int, int))foo); // fails, trailing Args is non-deduced context
暗示只有 void(int) member 用作参数值,这将成功推导出 Ret = voidArgs = {int} .

关于c++ - 使用给定的参数包消除重载函数的歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65203891/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com