gpt4 book ai didi

c++ - 在定义重载C++函数模板的原型(prototype)时,使用它的名字来引用之前的定义是否合法?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:42:34 25 4
gpt4 key购买 nike

假设我们想要重载函数模板f,但前提是尚未声明类似的重载:

template<typename T>
void f(T); // main prototype

struct A {};
struct B {};

//we want to declare B f(A), but only if something like A f(A) hasn't been declared
//we can try to check the type of expression f(A) before defining it
//and disable overload via enable_if
template<typename T = void> //it has to be a template to use enable_if
std::enable_if_t<std::is_same_v<void, decltype(T(), (f)(A{}))>, B> f(A);
// decltype expression depends on T, but always evaluates to the type of (f)(A{})
// parenthesis are used to disable ADL, so only preceding definitions are visible

代码被 Clang 接受,类似于 GCC(见 https://godbolt.org/g/ZGfbDW ),并在 Visual C++ 15.5 上导致编译器错误“递归类型或函数依赖上下文太复杂”。

我的问题是:这是符合 C++ 标准的合法声明还是涉及未定义的行为?

最佳答案

我相信这是一个法律声明,仅仅基于没有任何理由不这样做。

有几件事值得指出。首先,我们在这里对 f 有两种用法,它们是不同的:

template<typename T = void>
std::enable_if_t<std::is_same_v<void, decltype(T(), (f)(A{}))>, B> f(A);
// ^^^ ^^^
// #1 #2

我们在 #2 中声明了名称 f,但它不在 #1 中的使用范围内† - 它的声明点在完整的声明符之后,其中包括 enable_if_t block 。所以这里没有递归。如果 VS 有问题,我怀疑这可能与模板中名称查找的一般问题有关。

其次,这些模板在功能上并不等效 - 主原型(prototype)接受一个类型为模板参数的参数,而这个模板接受一个 A。功能等价的要点是以一种不需要逐个标记复制的方式将声明与定义相匹配——但我们在这个例子中的两个 f 函数模板是完全不同的。

我看不出有什么理由导致它格式错误。令人侧目,是的。病态的,不。


这会在尝试声明返回类型取决于自身的递归函数模板时导致一个相当常见的错误。例如:

template <size_t V>
using size_ = std::integral_constant<size_t, V>;

constexpr size_<0> count() { return {}; }

template <typename T, typename... Ts>
constexpr auto count(T, Ts... ts)
-> size_<decltype(count(ts...))::value + 1> { return {}; }

int main() {
static_assert(count() == 0); // ok
static_assert(count(1) == 1); // ok
static_assert(count(1, 2) == 2); // error: no matching function to call
}

关于c++ - 在定义重载C++函数模板的原型(prototype)时,使用它的名字来引用之前的定义是否合法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47668769/

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