簡體   English   中英

重載模板函數聲明順序

[英]Overloaded templated function declaration order

我有一些類似於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 ++使用兩階段名稱查找來解析在模板定義中找到的標識符。 (除非您有MSVC,它僅使用第二階段)。

聲明/定義模板時,將解析不依賴於模板參數的所有名稱。 實例化時,將解析不依賴模板參數的名稱。 這次,實例化時可見的名稱將參與並可以在查找過程中找到。

在您的情況下,內部的variantToMap調用取決於模板參數,因此只有在調用外部函數后才能解析它們。 到那時,所有4個變體都可見並且可以找到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM