模板实例化导致编译器未能识别decltype(auto)

错误信息重温

error: function ‘enqueue<(lambda at practice1.cpp:16:26)>’ with deduced return type cannot be used before it is defined
pool.enqueue([i] {
^
./threadpool.h:23:24: note: ‘enqueue<(lambda at practice1.cpp:16:26)>’ declared here
decltype(auto) enqueue(F&& f, Args&&… args);
^
1 error generated.

错误例子

由于源代码过于冗长,采用另外一个例子举出问题

a.h

class Calculator {
    Calculator();
    template<typename... Args>
    static auto add(Args... args);
};

a.cpp

#include "Calculator.h"
Calculator::Calculator() {}
template<typename... Args>
auto Calculator::add(Args... args) {
    return (args + ... + 0);
}

main.cpp

#include <iostream>
#include "Calculator.h"

int main(){
    Calculator cal;
    std::cout<< cal.add(1,2,3);
}

按照此顺序进行一个编译的话,可以有两种情况

第一种,基于a.cpp 编译成 .o 文件与 main.cpp链接然后生产可执行文件

第二种,a.cppmain.cpp 一起编译生产可执行文件

两种结果是一致的

显示错误

Function ‘add<int, int, int>’ with deduced return type cannot be used before it is defined

​ 但是如果将add() 的实现移去a.h 文件当中,就没有错误信息的产生了。

原因

​ 原因在于,正在尝试定义函数之前使用推导的返回类型,这是不允许的

  1. main.cpp ,调用add() 函数的时候,这个函数的模板还未进行实例,直接原因在于它们不是在一个编译单元中定义的
  2. 显式声明返回类型而不使用自动推导

深入

由于其核心原因在于实例化模板的时候,实现不在.h 的文件下,编译器无法实例化模板,导致无法访问

例子

在实例化模板时,编译器会使用给定的模板参数创建一个新类。例如:

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f;

读到这一行的时候,编译器会新建一个类(可以称之为FooInt)模板实例化的过程

struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

因此,编译器需要访问方法的实现,以使用模板参数(在本例中int)实例化它们。如果这些实现不在标头中,它们将无法访问,因此编译器将无法实例化模板。

解决方法

解决方法一

一个常见的解决方案是在头文件中编写模板声明,然后在实现文件(例如 .tpp)中实现类,并在头文件的末尾包含这个实现文件。

a.h

// 后面加上
#include "a.tpp"

a.cpp 更名为 a.tpp ,其主要作用是a.h 的类方法补充

其余不变

这样,实现了声明与实现分离,且编译器可以访问

解决方法二

另一种解决方案是保持实现分离,并显式实例化您需要的所有模板实例:

Foo.h

// no implementation
template <typename T> struct Foo { ... };

Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

借鉴

https://stackoverflow.com/questions/59381133/c-deduced-return-type-cannot-be-used-before-it-is-defined

https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值