CRTP:从派生类调用基函数时出现类型转换错误

问题描述 投票:0回答:1

我是 CRTP 和大量模板化代码的新手,所以我不确定这是否可能......

我有一个模板类如下:

template<typename ...T>
class base_type_components
{
public:
    template<std::size_t i>
    std::tuple_element_t<i, std::tuple<T...>>
    component()
    {
        return std::get<i>(_components);
    }

    constexpr std::size_t
    num_components() const
    {
        return sizeof...(T);
    }
private:
    std::tuple<T...> _components;
};

该父类采用类型列表并生成用于“组件存储”的元组。
我可以通过调用

x.component<0>()
, &c 来访问这些组件。然而我的子类也是一个模板,所以我实际上在内部使用
this->template component<0>()

我的子类定义如下:

template<std::size_t L = 199>
class type_derived_st :
    public base_type_components<std::string>
{
public:
    std::string
    value() const
    {
        return this->template component<0>();
    }

    ...
};

这个类也是一个模板。模板 arg

L
在与问题无关的其他代码中使用。

问题出在

type_derived_st<L>::value
的 return 语句上。
当我将类实例化为
type_derived_st<5>
并尝试运行
value
函数时,出现以下编译时错误:

错误:无法将

'const type_derived_st<5>*'
转换为
'base_type_components<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >*'

我不明白是什么阻碍了这里的转换?

如果我执行以下操作:

type_derived_st<5> x;
std::string s = x.component<0>();

然后就完美运行了。只有当我尝试在模板派生类内部调用该函数时,才会出现此错误:

type_derived_st<5> x;
std::string s = x.value(); // error!

MRE:

#include <cstddef>
#include <string>
#include <tuple>

template<typename ...T>
class base_type_components
{
public:
    template<std::size_t i>
    std::tuple_element_t<i, std::tuple<T...>>
    component()
    {
        return std::get<i>(_components);
    }

    constexpr std::size_t
    num_components() const
    {
        return sizeof...(T);
    }
private:
    std::tuple<T...> _components;
};

template<std::size_t L = 199>
class type_derived_st :
    public base_type_components<std::string>
{
public:
    type_derived_st() = default;
    ~type_derived_st() = default;

    std::string
    value() const
    {
        return this->template component<0>();
    }
};

int
main()
{
    type_derived_st<5> x;
    std::string y = x.value();

    return 0;
}
c++ templates c++17 crtp
1个回答
0
投票

首先,这不是CRTP的情况。在 CRTP 中,派生类将位于基类的模板参数中:

template<class T>
class base {};

class derived : public base<derived> {};

现在,真正的问题是您正在尝试从

const
限定函数
component<0>()
调用非
const
限定函数
value()
。您还需要使
component<0>()
const
合格。如果您确实希望类的用户能够修改
i
处的组件,请提供两个重载并通过引用返回值:

template <typename... T>
class base_type_components {
public:
    template <std::size_t I>
    auto const& component() const {       // this will be used by value()
//       ^^^^^^             ^^^^^
        return std::get<I>(_components);
    }
    template <std::size_t I>
    auto& component() {                   // here component I is mutable
//      ^
        return std::get<I>(_components);
    }

private:
    std::tuple<T...> _components;
};

你也不需要

this->template
。正常调用该函数即可:

template <std::size_t L = 199>
class type_derived_st : public base_type_components<std::string> {
public:
    type_derived_st() = default;
    ~type_derived_st() = default;

    std::string value() const { return component<0>(); }
//                                     ^^^^^^^^^^^^^^
};
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.