C++ 尝试使用继承和模板实现CRTP。Visual Studio正在生成编译器错误

C++ 尝试使用继承和模板实现CRTP。Visual Studio正在生成编译器错误,c++,compiler-errors,visual-studio-2017,c++17,crtp,C++,Compiler Errors,Visual Studio 2017,C++17,Crtp,这是前一个问题的延续,用户建议使用CRTP来解决我的问题。我试图采纳他们的建议,当我尝试将其应用到我的总线类时,Visual Studio正在生成编译器错误 当我尝试这样做时: template<size_t BusSize> class Bus : public Component, ComponentID<Bus> { 模板 类总线:公共组件,组件ID{ 我得到这个错误: >------ Build started: Project: Simulator,

这是前一个问题的延续,用户建议使用
CRTP
来解决我的问题。我试图采纳他们的建议,当我尝试将其应用到我的
总线
类时,Visual Studio正在生成编译器错误

当我尝试这样做时:

template<size_t BusSize>
class Bus : public Component, ComponentID<Bus> {
模板
类总线:公共组件,组件ID{
我得到这个错误:

>------ Build started: Project: Simulator, Configuration: Debug x64 ------
1>main.cpp
1>c:\***\bus.h(6): error C3203: 'Bus': unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type
1>c:\***\bus.h(49): note: see reference to class template instantiation 'Bus<BusSize>' being compiled
1>Done building project "Simulator.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
----构建已启动:项目:模拟器,配置:调试x64------
1> main.cpp
1> c:\***\bus.h(6):错误C3203:“总线”:非专用类模板不能用作模板参数“t”的模板参数,应为实类型
1> c:\***\bus.h(49):注意:请参阅正在编译的类模板实例化“bus”的参考
1> 完成构建项目“Simulator.vcxproj”--失败。
======生成:0成功,1失败,0最新,0跳过==========
当我尝试将其更改为:

template<size_t BusSize>
class Bus : public Component, ComponentID<Bus<BusSize>> {
模板
类总线:公共组件,组件ID{
然后它给了我这些错误:

>------ Build started: Project: Simulator, Configuration: Debug x64 ------
1>main.cpp
1>c:\***\bus.h(11): error C2512: 'ComponentID<Bus<4>>': no appropriate default constructor available
1>c:\***\bus.h(6): note: see declaration of 'ComponentID<Bus<4>>'
1>c:\***\bus.h(11): note: while compiling class template member function 'Bus<4>::Bus(const std::string &)'
1>c:\***\main.cpp(10): note: see reference to function template instantiation 'Bus<4>::Bus(const std::string &)' being compiled
1>c:\***\main.cpp(10): note: see reference to class template instantiation 'Bus<4>' being compiled
1>c:\***\bus.h(11): error C2614: 'Bus<4>': illegal member initialization: 'ComponentID' is not a base or member
1>Done building project "Simulator.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
----构建已启动:项目:模拟器,配置:调试x64------
1> main.cpp
1> c:\***\bus.h(11):错误C2512:“ComponentID”:没有合适的默认构造函数可用
1> c:\***\bus.h(6):注:参见“组件ID”的声明
1> c:\***\bus.h(11):注意:在编译类模板成员函数“bus::bus(const std::string&)”时
1> c:\***\main.cpp(10):注意:请参阅正在编译的函数模板实例化“Bus::Bus(const std::string&)”的参考
1> c:\***\main.cpp(10):注意:请参阅正在编译的类模板实例化“总线”的参考
1> c:\***\bus.h(11):错误C2614:“总线”:非法成员初始化:“ComponentID”不是基或成员
1> 完成构建项目“Simulator.vcxproj”--失败。
======生成:0成功,1失败,0最新,0跳过==========

我不知道还有什么可以尝试解决这些编译器错误

这是我的源代码

main.cpp

#include <exception>

#include "Bus.h"

int main() {
    try {
        Wire w1, w2, w3, w4;
        std::cout << w1.id() << " " << w2.id() << " " << w3.id() << " "<< w4.id() << "\n\n";

        Bus<4> b1;

        b1.connect(&w1, 0);
        b1.connect(&w2, 1);
        b1.connect(&w3, 2);
        b1.connect(&w4, 3);

        b1.connect(&w1, 1);  // Valid Connection: same wire to multiple bus wires
        b1.connect(&w1, 0);  // Invalid Connection: trying to connect a same wire to the same bus wire multiple times...
        std::cout << "\n";

        Bus<4> b2;
        w1.connect(&w2);
        w2.connect(&w3);
        w3.connect(&w4);
        w4.connect(&w1);
        std::cout << "\n";

        b2.connect(&b1.wire(0), 0);
        b2.connect(&b1.wire(1), 1);
        b2.connect(&b1.wire(2), 2);
        b2.connect(&b1.wire(3), 3);

        std::cout << "\nThese are my connected components:\n";
        for( size_t i = 0; i < b2.size(); i++ ) {
            for (auto& component : b2.myConnections(i)) {
                std::cout << "\t" << component->id() << " has ";
                auto connections = component->myConnections();
                for (auto& c : connections) {
                    std::cout << c->id() << " ";
                }
                std::cout << '\n';
            }
            std::cout << '\n';
        }
                     
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
#包括
#包括“Bus.h”
int main(){
试一试{
导线w1、w2、w3、w4;

std::cout第二次尝试设置基类是正确的,您只需添加对基类构造函数的调用,因为它没有默认构造函数:

template<size_t BusSize>
class Bus : public Component , ComponentID<Bus<BusSize>> {
private:
    std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;

public:
    explicit Bus(const std::string& name = "Bus") : Component(name), ComponentID<Bus<BusSize>>(id_) {        
        createBus();
    }
模板
类总线:公共组件,组件ID{
私人:
std::阵列总线接口;
公众:
显式总线(const std::string&name=“Bus”):组件(名称),组件id(id_417;{
createBus();
}
通常使用类型别名来简化此过程:

template<size_t BusSize>
class Bus : public Component , ComponentID<Bus<BusSize>> {
private:
    using BusComponentID = ComponentID<Bus<BusSize>>;
    std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;

public:
    explicit Bus(const std::string& name = "Bus") : Component(name), BusComponentID(id_) {        
        createBus();
    }
模板
类总线:公共组件,组件ID{
私人:
使用BusComponentID=ComponentID;
std::阵列总线接口;
公众:
显式总线(const std::string&name=“Bus”):组件(名称),总线组件id(id_417;{
createBus();
}

我找到了解决问题的方法…我仍然不明白为什么Visual Studio会给我编译器错误

在查看代码并看到CRTP的模式在使用中并且没有修改它之后…我发现了一种有效的方法,它对我来说是有效的

在我的
总线
类中,它本身是模板化的,但没有使用
类型名
类型
…这让我思考并知道当前的
CRTP
对于未模板化的
Wire
类来说工作得很好…我选择做以下工作

我创建了另一个抽象基类…它是
Component
Bus
之间的中间层…正是这个非模板化的抽象类继承了
Component
ComponentID
。然后我只有
Bus
继承自
busatract

我的代码的其余部分仍然是相同的,除了在自动命名id生成的构造函数中有一些小的变化……下面是我的
Bus
类的结果

总线h

#pragma once

#include <assert.h>
#include <memory>  
#include <array>
#include <list>       
#include <iomanip>
#include <iostream>    
#include <string>
#include <sstream>    

// I added this class template to handle the `ID's` as suggested to remove the code duplication...
template<class T>
class ComponentID {
public:
    explicit ComponentID(std::string& id) {
        static int i = 0;
        std::stringstream strValue;
        strValue << std::setw(3) << std::setfill('0') << std::to_string(i++);
        id.append("_" + strValue.str());
    }
};

class Component {
protected:
    std::string id_ = "";
    std::list<std::shared_ptr<Component>> components_;

    explicit Component(const std::string& id) : id_{ id } {}

public:
    virtual ~Component() {}

    std::string& id() { return id_; }

    void connect(Component* other) {
        for (auto& l : components_) {
            if (other->id_ == l->id()) {
                std::cout << "Component " << other->id_ << " already exists in " << id_ << "!\n";
                return;
            }
        }
        components_.push_back( std::make_shared<Component>( *other ) );
        std::cout << "Successfully connected " << other->id() << " to " << id_ << "\n";
    }

    virtual std::list<std::shared_ptr<Component>> myConnections() { return components_; }
    virtual void propagate() {};
};
#pragma once

#include "Component.h"

// I added ComponentID as an inherited base,
// I removed the `updateID()` function from this class,
// and I removed the call to it from within the constructor
class Wire : public Component, ComponentID<Wire> {
private:

public:
    explicit Wire(const std::string& name = "Wire") : Component(name), ComponentID(id_) {
        //updateId();
    };
       
    virtual ~Wire() {}

    virtual void propagate() override {
        return;
    }        
};
#pragma once

#include "Wire.h"

// I'm trying to do the same as I did in my Wire class through inheritance...
// I also removed the updateID() function and the call to it with the constructor
// However, this is generating a compiler error.
template<size_t BusSize>
class Bus : public Component, ComponentID<Bus> {
private:
    std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;

public:
    explicit Bus(const std::string& name = "Bus") : Component(name), ComponentID(id_) {        
        createBus();
    }

    virtual ~Bus() {}

    virtual void propagate() override {
        return;
    }

    void connect(Component* component, size_t index) {
        assert(index < BusSize);
        assert(component != nullptr);
        bus_interface_[index]->connect(component);
        std::cout << "\t from " << component->id() << " to " << id_ << "\n";
    }

    Wire wire(size_t index) {
        assert(index < BusSize);
        return *bus_interface_[index].get();
    }

    std::array<std::shared_ptr<Wire>, BusSize> bus() { return bus_interface_; }

    std::list<std::shared_ptr<Component>> myConnections(size_t index) { 
        assert(index < BusSize);
        return bus_interface_[index]->myConnections();
    }

    size_t size() const { return BusSize; }

private:
    void createBus() {
        size_t i = 0;
        for (auto& w : bus_interface_) {
            w = std::shared_ptr<Wire>(new Wire);
        }
    }
};
#pragma once

#include "Wire.h"

class BusAbstract : public Component, ComponentID<BusAbstract> {
protected:
    explicit BusAbstract(const std::string& name = "Bus") : Component(name), ComponentID(id_) {}
};

template<size_t BusSize>
class Bus : public BusAbstract {
private:
    std::array<std::shared_ptr<Wire>, BusSize> bus_interface_;

public:
    explicit Bus(const std::string& name = ("Bus<" + std::to_string(BusSize) + ">")  ) : BusAbstract(name) {        
        createBus();
    }

    virtual ~Bus() {}

    virtual void propagate() override {
        return;
    }

    void connect(Component* component, size_t index) {
        assert(index < BusSize);
        assert(component != nullptr);
        bus_interface_[index]->connect(component);
        std::cout << "\t from " << component->id() << " to " << id_ << "\n";
    }

    Wire wire(size_t index) {
        assert(index < BusSize);
        return *bus_interface_[index].get();
    }

    std::array<std::shared_ptr<Wire>, BusSize> bus() { return bus_interface_; }

    virtual std::list<std::shared_ptr<Component>> myConnections(size_t index) { 
        assert(index < BusSize);
        return bus_interface_[index]->myConnections();
    }

    size_t size() const { return BusSize; }

private:
    void createBus() {
        size_t i = 0;
        for (auto& w : bus_interface_) {
            w = std::shared_ptr<Wire>(new Wire(this->id() + "_Wire"));
        }
    }
};
#pragma一次
#包括“Wire.h”
类BusAbstract:公共组件,ComponentID{
受保护的:
显式BusAbstract(const std::string&name=“Bus”):组件(名称),组件id(id_){
};
模板
类总线:公共总线摘要{
私人:
std::阵列总线接口;
公众:
显式总线(const std::string&name=(“总线”):总线抽象(name){
createBus();
}
虚拟~Bus(){}
虚空传播()重写{
返回;
}
无效连接(组件*组件,大小索引){
断言(索引<总线大小);
断言(组件!=nullptr);
总线\接口\索引->连接(组件);

std::cout如果
ComponentID
没有引用
t
模板参数,为什么它是一个模板类?@selbie我遵循原始问题中建议答案的结构…他们将ComponentID模板化,然后所有子组件类都继承自该模板类…以及ComponentID模板te argument是从它继承的类…这是我从他们的建议中理解的…无论如何,我只是将您的所有代码粘贴到一个源文件中并编译了它。没有问题。您使用的是Visual Studio的哪个版本?@selbie我希望每个子类类型独立地增加它们自己附加到I的值r字符串id…例如,我只有一根导线和一个总线类atm…因此,如果我创建了4根导线和2根总线,那么它们应该如下:
Wire\u 000
Wire\u 001
Wire\u 002
Wire\u 003
Bus\u 001
…不确定这是否与此有关,但应包括
真的是
\include
?我注意到,当我编译你的代码时,我必须解决这个问题。回答很好,但我用了一种稍微不同的方法解决了它,现在它开始工作了。。。