【问题标题】:Compile error in full specialisation of function template函数模板全特化编译错误
【发布时间】:2021-09-08 14:35:06
【问题描述】:

在以下程序中,我尝试使用类型的元结构迭代类型列表。

除非我在基本打印模板定义之前指定template<>,否则它可以编译并正常工作。

/* example.cpp */
#include <iostream>


template<typename ...>
struct List{};

template<typename T,typename ...Rest>
void print(List<T,Rest ...> *) {
    std::cout << typeid(T).name() << std::endl;
    print((List<Rest ...> *)nullptr);
}

// uncommenting the next line creates compilation error
// template<>
void print(List<> *) {
    
}

int main() {

    using L = List<int,double,float>;

    print((L*)nullptr);
}

/* compile and execution
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
g++ -std=c++11 example.cpp
./a.out
i
d
f
*/

如果我在 void print(List&lt;&gt; *) 定义之前取消注释 template&lt;&gt;,g++ 和 clang++ 都会显示错误。

// clang++ error
error.cpp:15:6: error: no function template matches function template specialization 'print'
void print(List<> *) {
     ^
error.cpp:8:6: note: candidate template ignored: failed template argument deduction
void print(List<T,Rest ...> *) {
     ^
1 error generated.

我不明白为什么这种形式的完全专业化不适用于template&lt;&gt; 作为模板标题?我在这里缺少一些函数模板规则吗?

谢谢!

更新:

当我添加了一个额外的强制模板参数U时,以下程序编译并运行良好。

#include <iostream>


template<typename ...>
struct List{};

template<typename U,typename T,typename ...Rest>
void print(U* , List<T,Rest ...> *) {
    std::cout << typeid(T).name() << std::endl;
    print((int*)nullptr, (List<Rest ...> *)nullptr);
}

// I dont understand, that `T` is missing here, but still compiles
template<typename U>
void print(U *,List<> *) {
    
}

int main() {

    using L = List<int,double,float>;

    print((int*)nullptr,(L*)nullptr);
}

我不明白第一个程序中the error的原因和第二个程序中no error的原因。

【问题讨论】:

  • 模板函数专业化是一个蠕虫罐头。重载它们只是更容易推理。

标签: c++ templates


【解决方案1】:

您的主要模板是:

template&lt;typename T, typename...Rest&gt; void print(List&lt;T, Rest...&gt; *)

所以一个T 和一包。

template&lt;&gt; void print(List&lt;&gt; *) 根本不匹配。

你必须有

template&lt;typename...Ts&gt; void print(List&lt;Ts...&gt; *) 允许您的专业化。

注意,与 C++17 的折叠表达式相比,它只是

template<typename ... Ts>
void print(List<Ts...>) {
    ((std::cout << typeid(Ts).name() << std::endl), ...);
}

int main()
{
    using L = List<int, double, float>;

    print(L{});
}

【讨论】:

  • 嗨,我用一个额外的模板参数更新了 QS,它可以编译。我不明白第一个程序中the error的原因和第二个程序中no error的原因。
  • @Debashish:在你的第二个 sn-p 中,你也做重载,而不是专业化。
  • 啊,我需要了解一下模板重载和专业化之间的区别。
【解决方案2】:

请注意,模板的默认定义至少需要一个参数。所以特化必须至少有一个参数。

所以替代解决方案:

template<typename ...>
struct List{};

template<typename T,typename ...Rest>
void print(List<T,Rest ...> *) {
    print((List<T>*)nullptr);
    print((List<Rest ...> *)nullptr);
}

template<typename T>
void print(List<T> *) {
    std::cout << typeid(T).name() << std::endl;
}

https://godbolt.org/z/GhhWdfoj3

【讨论】:

  • 不,不是,他的代码是这样的:godbolt.org/z/TYovz99qG
  • Working OP 的代码是that,递归结束于 0 而不是你的 1。两者都使用重载。
【解决方案3】:

您的问题的原因是模板 为空。考虑将其替换为:

template<typename T>

或者类似的东西。这完全取决于你:)

【讨论】:

  • 请记住,我不会讲太多细节来迷惑任何人,所以这样做应该可行。
  • 问题是这样做不能按 OP 的预期工作。您是否尝试过使用您提出的解决方案编译代码?
  • 是的。它编译得很好。
  • template&lt;typename T&gt; void print(List&lt;&gt; *) 在这种情况下,T 永远无法推导出来。我不确定你是如何编译它的。 Here's the code not compiling。替换您提到的那行根本行不通。
猜你喜欢
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多