我正在尝试初始化一个基类的const std::vector<std::string>
成员对象,并使用一个由派生类传递的编译时字符串组成的向量。派生类将定义向量中的某些字符串,向量中其余的字符串将由派生类的子类(即从派生类派生的类)定义。
例如:
// +----------------+
// | ConfigBaseUnit |
// +----------------+
class ConfigBaseUnit
{
public:
ConfigBaseUnit(std::vector<std::string> &&fields);
virtual ~ConfigBaseUnit() = 0;
private:
const std::vector<std::string> field_vector;
};
ConfigBaseUnit::ConfigBaseUnit(std::vector<std::string> &&fields)
: field_vector(std::move(fields)) {
}
ConfigBaseUnit::~ConfigBaseUnit(){}
// +----------+
// | Ioconfig |
// +----------+
class Ioconfig : public ConfigBaseUnit
{
public:
Ioconfig(std::vector<std::string> &&fields);
virtual ~Ioconfig() {};
};
std::vector<std::string> & vect_concat(
std::vector<std::string> &&v1,
std::vector<std::string> &&v2 )
{
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
Ioconfig::Ioconfig(std::vector<std::string> &&fields)
: ConfigBaseUnit( std::move(
vect_concat({ "label", "protocol", "connected" }, std::move(fields))
)
) {
}
// +-------------------+
// | Ioconfig_Ethernet |
// +-------------------+
class Ioconfig_Ethernet : public Ioconfig
{
public:
Ioconfig_Ethernet();
virtual ~Ioconfig_Ethernet() final {};
};
Ioconfig_Ethernet::Ioconfig_Ethernet()
: Ioconfig( { "ip", "port" } ) {
}
ConfigBaseUnit
使用其class-constructor参数初始化其const field_vector
成员。
ConfigBaseUnit::ConfigBaseUnit(std::vector<std::string> &&fields)
: field_vector(std::move(fields)) {
}
派生类Ioconfig
希望field_vector
的初始化始终包含以下各项:
{ "label", "protocol", "connected" }
,但是field_vector
还应包括Ioconfig_Ethernet
(从Ioconfig
派生)发送的项目。例如,Ioconfig_Ethernet
将这些转发给包含在内:
{ "ip", "port" }
Ioconfig
将其在其构造函数中像这样绑在一起:
Ioconfig::Ioconfig(std::vector<std::string> &&fields)
: ConfigBaseUnit{ std::move(
vect_concat({ "label", "protocol", "connected" }, std::move(fields))
)
} {
}
Ioconfig
构造函数使用函数vect_concat(...)
将字段合并到最终向量中,然后将其移至基类。
vect_concat
就是:
std::vector<std::string> & vect_concat(
std::vector<std::string> &&v1,
std::vector<std::string> &&v2 )
{
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
现在到了重点
这可行,但是我希望vect_concat
成为 constexpr
函数。最终,ConfigBaseUnit::field_vector
中的值应在编译时定义。它的内容应该是固定的,硬编码的,纯文本的值,可以通过读取代码轻松找到(即,永远不会从文件或命令行arg等中读取它们)。
仅将vect_concat
定义为constexpr
不起作用,大概是因为std :: vector :: insert不是constexpr。我该如何解决?
vect_concat
声明为模板可以使我将其设置为constexpr
函数。
这有效:
template <class V>
constexpr V & vect_concat(V &&v1, V &&v2)
{
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
这不是:
constexpr std::vector<std::string> & vect_concat(
std::vector<std::string> &&v1,
std::vector<std::string> &&v2 )
{
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
所以,我的问题(不幸的是,在撰写本文时不断演变):
std::vector::insert
,它似乎不是constexpr函数。constexpr
说明符是否被忽略?答案 0 :(得分:2)
如果
constexpr
函数的实例化模板专门化 模板或类模板的成员函数将无法满足constexpr
函数或constexpr
构造函数的要求, 该专业化仍然是constexpr
函数或constexpr
构造函数,即使对该函数的调用不能出现在 常数表达式。
从标准中可以看到,constexpr
不会被忽略,但是当您尝试将其用作常量时,则不应编译它。
总的来说,这只是对您原始请求的答案,以防您拥有vect_concat()
和constexpr
的唯一原因是在代码中表达了意图(这是值得的。在自己的权利!)。但是,如果在任何时候继续前进,您都可以尝试将其称为语法常量,那么它将表明自己丢失了constexpr
本身的整个要点。
答案 1 :(得分:0)
标记为“ constexpr”的方法仅在编译时知道传递的参数的情况下,才在编译时进行评估。模板是在编译时制作的,因此它知道传入的内容,因此可以正常工作。然后,当您传入初始化程序时,它可以在编译时构造向量。否则,“ constexpr”方法将在运行时像其他任何方法一样进行评估。