模板别名、变量模板和自动类型推导无法推导模板参数

Posted

技术标签:

【中文标题】模板别名、变量模板和自动类型推导无法推导模板参数【英文标题】:Template Alias, Variable Template, and auto type deduction failing to deduce template argument 【发布时间】:2019-11-29 09:06:11 【问题描述】:

在处理我的类声明时,我在尝试使用自动类型推导时如何在非类模板中使用别名模板和模板变量有些困惑。

Signal.h

#ifndef SIGNAL_H
#define SIGNAL_H

#include <cstdint>

template<typename T>
using TimeSignal = T;

using DiscreteTime = TimeSignal<std::uint8_t>;
using ContinuousTime = TimeSignal<double>;

class Signal 
private:
    template<typename T>
    static TimeSignal<T> time_;

    double voltage_;
    double current_;

public:
    template<typename T>
    explicit Signal( TimeSignal<T> time, double voltage = 0, double current = 0 ) :
        voltage_voltage, current_current
     time_ = time; 

     double sampleVoltage()  return voltage_; 
     double sampleCurrent()  return current_; 

     template<typename T>
     static auto atTime()  return time_;          
;

#endif // SIGNAL_H

我会这样使用它:

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

int main() 
    DiscreteTime t1 5 ;
    ContinuousTime t2 7.5 ;

    Signal s1 t1, 3.5, 0.05 );
    Signal s2 t2, 4.3, 0.09 );

    auto time1 = s1.atTime();
    auto time2 = s2.atTime();

    return 0;

我不想模板化这个类,所以我想有一个内部变量模板。在课堂之外,我试图使用模板别名来描述不同的“TimeSignals”,因为“DiscreteTime”通常是和integral typeContinousTime 是浮点数或实数集。然而,我正在模板这个类的构造函数,它接受TimeSignal 类型,并希望类根据传入的两种类型中的哪一种来推断或自动解析它的内部变量模板。最后我试图使用自动类型推导返回该类型。

我不知道是语法还是用法,但这让我很难过。我不确定如何使它进入工作编译状态。

这是 Visual Studio 2017 给我的当前编译器错误。

1>------ Build started: Project: Circuit Maker Simulator, Configuration: Debug x64 ------
1>main.cpp
1>c:\...\main.cpp(15): error C2672: 'Signal::atTime': no matching overloaded function found
1>c:\...\main.cpp(15): error C2783: 'auto Signal::atTime(void)': could not deduce template argument for 'T'
1>c:\...\Signal.h(64): note: see declaration of 'Signal::atTime'
1>c:\...\main.cpp(24): error C2672: 'Signal::atTime': no matching overloaded function found
1>c:\...\main.cpp(24): error C2783: 'auto Signal::atTime(void)': could not deduce template argument for 'T'
1>c:\...\Signal.h(64): note: see declaration of 'Signal::atTime'
1>Done building project "Circuit Maker Simulator.vcxproj" -- FAILED.

编译器错误对于他们所说的很明显,但就像他们在没有任何帮助、帮助或如何解决或解决此问题的建议的情况下对我尖叫或大喊大叫...

编辑

用户rafix07 的回答给了我很多帮助,而且很有帮助。我遗漏了几件事,如果我一直盯着它看足够长的时间,我可能最终会发现其中两件事,那就是在需要它的模板参数或参数的类中使用变量模板。另一种是在主函数中使用范围解析运算符来调用静态函数。过一段时间我就能找到它们。

让我陷入困境的一个问题是,我必须在调用它时显式地实例化我想要的类型的函数模板。这就是让我为我们的头发拔掉头发的那个......

根据他答案中的链接调整代码后,我现在可以编译,但是我现在收到未解析外部符号的链接器错误,它与模板变量有关。这应该不是问题,只需要在cpp文件中定义它来解析静态变量。

【问题讨论】:

【参考方案1】:

首先,atTime 是静态方法,因此调用它的唯一方法是使用范围解析运算符::atTime 不带参数,所以T 无法推导出来,您需要将 type 显式放入模板参数列表中:

auto time1 = Signal::atTime<DiscreteTime>();
auto time2 = Signal::atTime<ContinuousTime>();

SignalatTime 函数的 ctor 中,您必须指定 T 访问哪个变量模板:

template<typename T>
explicit Signal( TimeSignal<T> time, double voltage = 0, double current = 0 ) :
    voltage_voltage, current_current
 time_<T> = time; 

Full working code is here.

【讨论】:

好吧,我差一点就错过了一些东西,并且一直在使用我的编译器。我在 2 或 3 个地方遗漏了 time_&lt;T&gt;,然后主要是,暗指我的最大的事情不是范围解析运算符,我可以想出那么多,但明确声明要使用哪个函数这是我真正想念的。我按照您的代码示例进行了编译,但是现在我得到了链接器错误:来自变量模板的两个版本的未解析的外部符号。 @FrancisCugler Ups,我的错误,因为time_ 是静态的,我们必须在.cpp 文件中的某处定义它,在.cpp 中添加template&lt;typename T&gt; TimeSignal&lt;T&gt; Signal::time_;(在任何类之外)。链接器错误将消失。 所以我基本上走在正确的轨道上,我的大部分语法和我尝试使用它们的上下文都是正确的;我只是错过了一个关键部分。拥有第二双甚至第三双眼睛通常会有所帮助。 哦,顺便说一句;对于DiscreteTime,我将内部类型从uint8_t 更改为uint64_t。除此之外,当我去打印时代的价值观时,它就像一个魅力;我不得不在cout 声明中宣传time1。将其更改为 uint64_t 我不必担心提升 unsigned char 以获得正确的输出结果,也不必担心变量的宽度和溢出。如果我需要节省内存,我总是可以选择 16 或 32 类型。

以上是关于模板别名、变量模板和自动类型推导无法推导模板参数的主要内容,如果未能解决你的问题,请参考以下文章

深入了解C++:auto与函数模板之推导规则辨析

深入理解函数模板

什么是模板推导中的部分排序程序

参数和返回类型中的模板类型推导

从std :: function中推导返回和参数类型作为模板函数参数传递?

C++类模板常见用途和注意实现