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