繁体   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