gpt4 book ai didi

c++ - 重载模板函数声明顺序

转载 作者:行者123 更新时间:2023-11-28 02:46:05 25 4
gpt4 key购买 nike

我有一些代码读起来像这样 SSCCE:

#include <map>
#include <string>
#include <functional>

using std::map;
using std::string;
using std::function;
using std::forward;

template<typename ToType, typename... FromTypes>
ToType construct(FromTypes&&... fromTypes) {
return ToType(forward<FromTypes>(fromTypes)...);
}

class Variant {
public:
map<string, Variant> toMap() const;
};

map<string, Variant> Variant::toMap() const {
return {
{"test", {}},
{"test1", {}},
};
}

// #1
template <typename MapType>
MapType variantToMap(Variant const& v) {
// I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet.
return variantToMap<MapType>(v, construct<typename MapType::key_type, string>, construct<typename MapType::mapped_type, Variant>);
}

// #2
template <typename MapType>
MapType variantToMap(Variant const& v, function<typename MapType::key_type(string)> const& keyConvert) {
// I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet.
return variantToMap<MapType>(v, keyConvert, construct<typename MapType::mapped_type, Variant>);
}

// #3
template <typename MapType>
MapType variantToMap(Variant const& v, function<typename MapType::mapped_type(Variant)> const& valueConvert) {
// I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet.
return variantToMap<MapType>(v, construct<typename MapType::key_type, string>, valueConvert);
}

// #4
template <typename MapType>
MapType variantToMap(Variant const& v, function<typename MapType::key_type(string)> const& keyConvert, function<typename MapType::mapped_type(Variant)> const& valueConvert) {
MapType res;
for (auto pair : v.toMap()) {
res[keyConvert(pair.first)] = valueConvert(pair.second);
}

return res;
}

int main() {
Variant a;

// #1
variantToMap<map<string, Variant>>(a);

// #2
{
int counter = 0;
variantToMap<map<int, Variant>>(a, [&counter](string) -> int { return ++counter; });
}

// #3
variantToMap<map<string, int>>(a, [](Variant) -> int { return 42; });

// #4
{
int counter = 0;
variantToMap<map<int, int>>(a, [&counter](string) -> int { return ++counter; }, [](Variant) -> int { return 42; });
}

return 0;
}

编译和工作正常。

但是,因为它被声明为乱序,所以我预计它会抛出错误。我认为它不是的原因与这些函数都是模板化的事实有关。然而,这仍然让我有些困惑,因为(例如)在 variantToMap #1 中调用 variantToMap #4 有 3 个参数,这意味着

Clang 和 GCC 是否不适本地接受了这些函数,或者这是允许的吗?如果允许,这样做的理由是什么?

应该注意的是,我已经对这些函数进行了重新排序,我只是好奇为什么它首先起作用。

最佳答案

C++ 使用 two phase name lookup解析在模板定义中找到的标识符。 (除非你有 MSVC,它只使用第二阶段)。

当声明/定义模板时,所有不依赖于模板参数的名称都会被解析。实例化时,解析依赖于模板参数的名称。这一次,实例化时可见的名称参与其中,并且可以在查找过程中找到。

在您的情况下,内部 variantToMap 调用取决于模板参数,因此在调用外部函数之前它们不会被解析。那时所有 4 个变体都可见并且可以找到。

关于c++ - 重载模板函数声明顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24377606/

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