简体   繁体   English

具有第二种模板类型的部分模板特化

[英]Partial template specialization with second template type

Its simplified version of my real problem.它是我真正问题的简化版本。 Why in the first case template specialization doesn't work?为什么在第一种情况下模板专业化不起作用?

If I swap first two functions then it will work.如果我交换前两个功能,那么它将起作用。

Strange, but it works with msvc 19...奇怪,但它适用于 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
}

Godbolt link螺栓链接

First, interesting find.首先,有趣的发现。 Took me a moment.花了我一点时间。

Second, there is no such thing as partial specialization of function template.其次,没有 function 模板的偏特化。

Full specialization is OK, so the second implementation will chose the specialization.完全专业化是可以的,所以第二个实现将选择专业化。

The first case is an overload resolution between two template functions, the more specialized will be chosen.第一种情况是两个模板函数之间的重载决议,将选择更专业的。 The compiler will first construct the overload list - with candidates for the call.编译器将首先构造重载列表 - 带有调用的候选者。

Here's the thing, void write_impl(const std::string &result, M m) won't be considered because it is not defined yet!事情是这样的, void write_impl(const std::string &result, M m)不会被考虑,因为它还没有定义! The point of instantiation is directly after the template's definition.实例化点直接在模板的定义之后。 So, only the first template is in the overload set, it will match because a string is iterable and the instantiation will fail because char is not.因此,只有第一个模板在重载集中,它将匹配,因为字符串是可迭代的,而实例化将失败,因为char不是。

This will raise the same error about foo :这将引发关于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);
}

Why does the second case work then?为什么第二种情况有效呢? Because the compiler will "look ahead" to see all possible specializations.因为编译器将“向前看”以查看所有可能的特化。 But they still have to be present at the point which would instantiate the specialization.但是它们仍然必须出现在实例化专业化的点上。 So, my belief here is that the second case is undefined behaviour, based on this answer .因此,我在这里的信念是,基于此答案,第二种情况是未定义的行为。 I am not very well versed in this dark corner of C++, I might be wrong here. C++这个阴暗的角落我不是很精通,这里我可能错了。

Why does MSCV work?为什么MSCV有效? Beats me, it is sometimes "special", maybe their point of instantiation is wrong, foo will incorrectly work too.打败我,它有时是“特殊的”,也许他们的实例化点是错误的, foo也会错误地工作。

The first case isn't a case of template specialization;第一种情况不是模板专业化的情况; it's function overloading.这是 function 过载。

Doesn't works because the first function call the second one that isn't declared.不起作用,因为第一个 function 调用未声明的第二个。 Switching the order, as you can see, works because the first (now second) know the declaration (and the definition too) of the second (now first).如您所见,切换顺序是有效的,因为第一个(现在是第二个)知道第二个(现在是第一个)的声明(以及定义)。

You can't have template partial specialization for functions in C++; C++ 中的函数不能有模板部分特化; only full specialization.只有完全专业化。

You really need a sort of partial specialization, you can pass through a class/struct and a function inside it.您确实需要一种部分专业化,您可以在其中传递一个类/结构和一个 function 。 You can partially specialize the struct/class.您可以部分专门化结构/类。

For example例如

#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);
 }

But, as you can see, isn't really handy.但是,正如您所看到的,它并不是很方便。

Obviously, if you don't need a partial-specialization-for-function emulation, and you are comfortable with different and overloaded template function (given that are calling each other) you can declare the first, declare and define the second and define the first;显然,如果您不需要针对功能的部分专业化仿真,并且您对不同的重载模板 function (假设它们相互调用)感到满意,则可以声明第一个,声明并定义第二个并定义第一的;

Something as某事作为

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