我是 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;
}
首先,这不是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>(); }
// ^^^^^^^^^^^^^^
};