gpt4 book ai didi

c++ - 在派生类中专门化基类的模板化成员函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:45:24 25 4
gpt4 key购买 nike

TL;DR;

编译以下代码以两个未解析的外部结束。

问题

有没有办法在基类中有一个未定义的模板化成员函数,并让该函数在派生类中部分特化,这样部分特化将仅限于定义它的派生类?

解释

如您所见serial_portliquid_crystal源自 stream基类。 stream类将提供一个统一的接口(interface)来将文本发送到不同的外围设备。每个派生自 stream 的类必须实现 print(char)处理与外围设备的低级通信的功能。除此之外,还有一个未定义的模板化版本的 print,它可以专门用于用户可能想要打印的任何自定义类型。

stream类具有 operator << 的模板化定义用于将数据写入流中。该接线员将调用 stream::print这将处理实际的打印。如你所见print(const char*)print(fill)已经定义了,因为我希望它们存在于 stream 的每个派生类中.

现在是引入错误的部分

我想与之通信的外围设备有一些基本命令(LCD:将光标移动到 x,y 坐标,串行端口:将波特率设置为 x)它们之间不可互换,这意味着 LCD 不知道如何更改波特率和串口没有可以移动到特定坐标的光标。我想通过 operator << 传递命令就像我对 fill 做的一样.每个命令都是一个新结构,包含命令所需的数据,并且会有一个特殊版本的 print处理它们中的每一个。

这在理论上可行,但在编译过程中失败,因为 print 的专用版本在派生类中定义,但 operator <<stream 中定义类(class)。当我将命令传递给流时,链接器会查找 print 的专门定义里面stream当然它失败了,因为那些根本不存在。

我该如何克服这个错误?我使用的是 Visual Studio 15 Preview 4,我没有更改任何编译器标志。

源代码

#include <iostream>

class stream
{
public:
struct fill
{
int n;
char ch;
};

stream()
{}

virtual ~stream()
{}

template <typename T>
stream& operator << (T t)
{
this->print(t);
return *this;
}

protected:
virtual void print(char) = 0;

template <typename T>
void print(T);
};

template <>
void stream::print<const char*>(const char* str)
{
while (*str != '\0')
this->print(*(str++));
}

template <>
void stream::print<stream::fill>(stream::fill f)
{
while (f.n > 0)
{
this->print(f.ch);
f.n--;
}
}

class serial_port : public stream
{
public:
struct set_baudrate
{
int baud;
};

using stream::stream;

private:
void print(char c) override
{
// TODO: print to the actual serial port
std::cout << c;
}

template <typename T>
void print(T t)
{
stream::print<T>(t);
}
};

template <>
void serial_port::print<serial_port::set_baudrate>(serial_port::set_baudrate)
{
this->print("set_baudrate");
}

class liquid_crystal : public stream
{
public:
struct move
{
int x;
int y;
};

using stream::stream;

private:
void print(char c) override
{
// TODO: print to a character LCD
std::cout << c;
}

template <typename T>
void print(T t)
{
stream::print<T>(t);
}
};


template <>
void liquid_crystal::print<liquid_crystal::move>(liquid_crystal::move)
{
this->print("move");
}

int main()
{
liquid_crystal lcd;
lcd << liquid_crystal::move{ 1, 2 };
serial_port serial;
serial << serial_port::set_baudrate{ 9600 };
}

编辑

查看 compiler output 问题更明显, 链接器正在寻找 void stream::print<liquid_crystal::move>(liquid_crystal::move)void stream::print<serial_port::set_baudrate>(serial_port::set_baudrate)但函数签名应该是 void liquid_crystal::print<liquid_crystal::move>(liquid_crystal::move)void serial_port::print<serial_port::set_baudrate>(serial_port::set_baudrate) .

最佳答案

main , 行:

lcd << liquid_crystal::move{ 1, 2 };

调用:

stream::operator<< <liquid_crystal::move>(liquid_crystal::move)

然后调用:

stream::print<liquid_crystal::move>(liquid_crystal::move)

但是stream::print函数仅为 const char* 定义和 stream::fill类型。

liquid_crystal::print未使用函数,因为它不是 stream::print 的重写(它隐藏了 stream::print 类中的 liquid_crystal)。为了从 stream 访问它使用 this (这是 stream* ,而不是 liquid_crystal* ), stream::print必须是虚拟的。但在这种情况下,这是不可能的,因为它是一个模板函数。

一般来说,虚拟模板函数设计问题的解决方案通常并不简单。但在这种特定情况下,最简单的方法可能是复制 operator<<在每个派生类中。但是,它在 stream::operator<< 的情况下不起作用。被调用,例如:

void func(stream& s) {
s << liquid_crystal::move{ 1, 2 };
}
int main() {
liquid_crystal lcd;
func(lcd);
}

关于c++ - 在派生类中专门化基类的模板化成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39808971/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com