簡體   English   中英

具有第二種模板類型的部分模板特化

[英]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.

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