【问题标题】:Compiler error from type-checking a template parameter类型检查模板参数的编译器错误
【发布时间】:2020-11-17 08:26:37
【问题描述】:

我正在尝试编写一个以不同方式处理不同模板参数的模板类。我希望该类支持两种数据类型:unsigned ints 和 std::strings,仅此而已。该类的行为需要根据它获得的类型而有所不同,因此我在构造函数中进行了一些类型检查。

这是我正在做的精简代码。

#include <iostream> 
#include <memory>
#include <utility> 
#include <map> 
typedef unsigned int uint;

template<typename input_id_t> class atom_t
{
    public:
        atom_t(input_id_t d) : 
            data(d)
         { }
        
        const input_id_t data;
};

template<typename input_id_t> using atom_ptr = std::shared_ptr<atom_t<input_id_t>>;
template<typename input_id_t> using atom_map_t = std::map<input_id_t, atom_ptr<input_id_t>>;

template<typename input_id_t> class abstract_t
{
    public:

        abstract_t()
        {
            if (typeid(input_id_t).name() == typeid(uint).name())
            {
                this->base_entry = std::make_shared<atom_t<input_id_t>>(0);
                this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>(0, this->base_entry));
            }
            else if (typeid(input_id_t).name() == typeid(std::string).name())
            {
                this->base_entry = std::make_shared<atom_t<input_id_t>>("");
                this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>("", this->base_entry));
            }
            else { throw "abstract_t template argument invalid!\n"; }
        }

        atom_ptr<input_id_t> base_entry; 

        atom_map_t<input_id_t> * a_map = new atom_map_t<input_id_t>;
};

int main() 
{
    abstract_t<uint> A;
} 

我有几个问题。

  1. 此代码产生的错误如下。我认为它们都与对std::pair 的调用有关,但有什么问题?我注意到删除 else if 子句可以解决它们。

    错误:没有用于初始化 'std::pair' 的匹配构造函数(又名 'pair>') this->a_map->insert(std::pair>("", this->base_entry));

    错误:由于要求 'is_constructible::value',static_assert 失败 "无法在 make_shared 中构造对象

    错误:'atom_t'的初始化没有匹配的构造函数

  2. 我意识到typeid(input_id_t).name() == typeid(uint/std::string).name() 方法很笨拙。有没有更好的方法来做到这一点?

【问题讨论】:

  • 您正在尝试使用const char* 构造一个unsigned int (input_id_t)?

标签: c++ templates compiler-errors


【解决方案1】:

问题在于编译器会尝试编译您的if 语句的else 分支,即使该分支从未被采用。对于 C++17 及更高版本,可以通过结合使用 std::is_same 和 if constexpr 来避免这种情况,如下所示:

    abstract_t()
    {
        if constexpr (std::is_same_v <input_id_t, uint>)
        {
            this->base_entry = std::make_shared<atom_t<input_id_t>>(0);
            this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>(0, this->base_entry));
        }
        else if constexpr (std::is_same_v <input_id_t, std::string>)
        {
            this->base_entry = std::make_shared<atom_t<input_id_t>>("");
            this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>("", this->base_entry));
        }
        else { throw "abstract_t template argument invalid!\n"; }
    }

这也回答了你的第二个问题。但我更喜欢Roland的回答,它更好地封装了两个构造函数。

Live demo

【讨论】:

    【解决方案2】:

    问题是您的 std::string 案例的代码仍然被编译,即使它没有被执行,并且您不能构造一个带有 "" 作为第一个参数的 pair&lt;int, atom_ptr&lt;int&gt;&gt;。这是编译器告诉你的。

    更好的方法是使用模板特化:

    template<typename input_id_t> class abstract_t {};
    
    template<> class abstract_t<uint> {
    public:
        typedef uint input_id_t;
        abstract_t()
        {
            this->base_entry = std::make_shared<atom_t<input_id_t>>(0);
            this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>(0, this->base_entry));
        }
    
        atom_ptr<input_id_t> base_entry; 
        atom_map_t<input_id_t> * a_map = new atom_map_t<input_id_t>;
    }
    
    template<> class abstract_t<std::string> {
    public:
        typedef std::string input_id_t;
        abstract_t()
        {
            this->base_entry = std::make_shared<atom_t<input_id_t>>("");
            this->a_map->insert(std::pair<input_id_t, atom_ptr<input_id_t>>("", this->base_entry));
        }
    
        atom_ptr<input_id_t> base_entry;
        atom_map_t<input_id_t> * a_map = new atom_map_t<input_id_t>;
    }
    

    【讨论】:

    • 感谢这个有用的答案!如果我使用您推荐的模板特化方法,我想包含在 abstract_t 中的其他成员函数是否也必须是特化的?
    • @DimitrijeKostic 是的,不同的专业就像独立的课程。您可以从包含通用功能的基类派生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 2020-10-13
    • 2013-10-13
    • 1970-01-01
    相关资源
    最近更新 更多