[英]Partial template specialization with second template type
它是我真正問題的簡化版本。 為什么在第一種情況下模板專業化不起作用?
如果我交換前兩個功能,那么它將起作用。
奇怪,但它適用於 msvc 19...
#include <string>
#include <vector>
#include <iostream>
template<typename T, typename M>
void write_impl(T &result, M m) {
for (const auto &i : result) {
write_impl(i, m);
}
}
template<typename M>
void write_impl(const std::string &result, M m) {
std::cout << result;
}
template<typename T>
void write_impl_1(T &result) {
for (const auto &i : result) {
write_impl_1(i);
}
}
template<>
void write_impl_1(const std::string &result) {
std::cout << result;
}
int main() {
std::vector<std::string> a{"42", "43", "44"};
write_impl(a, 42); // compile time error
write_impl_1(a); // works fine
}
首先,有趣的發現。 花了我一點時間。
其次,沒有 function 模板的偏特化。
完全專業化是可以的,所以第二個實現將選擇專業化。
第一種情況是兩個模板函數之間的重載決議,將選擇更專業的。 編譯器將首先構造重載列表 - 帶有調用的候選者。
事情是這樣的, void write_impl(const std::string &result, M m)
不會被考慮,因為它還沒有定義! 實例化點直接在模板的定義之后。 因此,只有第一個模板在重載集中,它將匹配,因為字符串是可迭代的,而實例化將失敗,因為char
不是。
這將引發關於foo
的相同錯誤:
#include <string>
#include <vector>
#include <iostream>
template<typename T>
void bar(T &result) {
foo();
}
void foo(){}
int main() {
std::vector<std::string> a{"42", "43", "44"};
bar(a);
}
為什么第二種情況有效呢? 因為編譯器將“向前看”以查看所有可能的特化。 但是它們仍然必須出現在實例化專業化的點上。 因此,我在這里的信念是,基於此答案,第二種情況是未定義的行為。 C++這個陰暗的角落我不是很精通,這里我可能錯了。
為什么MSCV有效? 打敗我,它有時是“特殊的”,也許他們的實例化點是錯誤的, foo
也會錯誤地工作。
第一種情況不是模板專業化的情況; 這是 function 過載。
不起作用,因為第一個 function 調用未聲明的第二個。 如您所見,切換順序是有效的,因為第一個(現在是第二個)知道第二個(現在是第一個)的聲明(以及定義)。
C++ 中的函數不能有模板部分特化; 只有完全專業化。
您確實需要一種部分專業化,您可以在其中傳遞一個類/結構和一個 function 。 您可以部分專門化結構/類。
例如
#include <string>
#include <vector>
#include <iostream>
template <typename T, typename M>
struct foo
{
static void bar (T & result, M m)
{
for (const auto &i : result)
foo<decltype(i), M>::bar(i, m);
}
};
template <typename M>
struct foo<std::string const &, M>
{
static void bar (std::string const & result, M)
{ std::cout << result; }
};
int main()
{
std::vector<std::string> a{"42", "43", "44"};
foo<decltype(a), int>::bar(a, 42);
}
但是,正如您所看到的,它並不是很方便。
顯然,如果您不需要針對功能的部分專業化仿真,並且您對不同的重載模板 function (假設它們相互調用)感到滿意,則可以聲明第一個,聲明並定義第二個並定義第一的;
某事作為
template <typename M>
void write_impl (std::string const &, M);
template<typename T, typename M>
void write_impl (T & result, M m)
{
for (const auto &i : result)
write_impl(i, m);
}
template <typename M>
void write_impl (std::string const & result, M m)
{ std::cout << result; }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.