【发布时间】:2019-02-14 21:35:56
【问题描述】:
在 Visual Studio 2017 中一切正常,但在 GCC (6.5.0) 中出现链接器错误。
这里有一些示例代码可以解决我的问题:
#include <iostream>
struct Foo{
static constexpr const char* s[] = {"one","two","three"};
};
int main(){
std::cout << Foo::s[0] << std::endl; //this works in both compilers
const char* const* str_ptr = nullptr;
str_ptr = Foo::s; //LINKER ERROR in GCC; works in VS
std::cout << str_ptr[1] << std::endl; //works in VS
return 0;
}
在 GCC 中,我得到 undefined reference to 'Foo::s'。我需要Foo::s 的初始化以留在结构的声明中,这就是我使用constexpr 的原因。有没有办法动态引用Foo::s,即使用指针?
更多背景信息
我现在将解释为什么我想这样做。我正在开发嵌入式软件来控制设备的配置。该软件加载包含参数名称及其值的配置文件。正在配置的参数集在编译时确定,但需要模块化,以便随着设备的开发继续添加新参数和扩展它们。换句话说,它们的定义需要在代码库中的一个地方。
我的实际代码库有数千行,可以在 Visual Studio 中运行,但这里有一个简化的玩具示例:
#include <iostream>
#include <string>
#include <vector>
//A struct for an arbitrary parameter
struct Parameter {
std::string paramName;
int max_value;
int value;
const char* const* str_ptr = nullptr;
};
//Structure of parameters - MUST BE DEFINED IN ONE PLACE
struct Param_FavoriteIceCream {
static constexpr const char* n = "FavoriteIceCream";
enum { vanilla, chocolate, strawberry, NUM_MAX };
static constexpr const char* s[] = { "vanilla","chocolate","strawberry" };
};
struct Param_FavoriteFruit {
static constexpr const char* n = "FavoriteFruit";
enum { apple, banana, grape, mango, peach, NUM_MAX };
static constexpr const char* s[] = { "apple","banana","grape","mango","peach" };
};
int main() {
//Set of parameters - determined at compile-time
std::vector<Parameter> params;
params.resize(2);
//Configure these parameters objects - determined at compile-time
params[0].paramName = Param_FavoriteIceCream::n;
params[0].max_value = Param_FavoriteIceCream::NUM_MAX;
params[0].str_ptr = Param_FavoriteIceCream::s; //!!!! LINKER ERROR IN GCC !!!!!!
params[1].paramName = Param_FavoriteFruit::n;
params[1].max_value = Param_FavoriteFruit::NUM_MAX;
params[1].str_ptr = Param_FavoriteFruit::s; //!!!! LINKER ERROR IN GCC !!!!!!
//Set values by parsing files - determined at run-time
std::string param_string = "FavoriteFruit"; //this would be loaded from a file
std::string param_value = "grape"; //this would be loaded from a file
for (size_t i = 0; i < params.size(); i++) {
for (size_t j = 0; j < params[i].max_value; j++) {
if (params[i].paramName == param_string
&& params[i].str_ptr[j] == param_value) {
params[i].value = j;
break;
}
}
}
return 0;
}
如您所见,其中涉及枚举和字符串数组,它们需要匹配,因此出于维护目的,我需要将它们保存在同一个位置。此外,由于此代码已经编写好并将在 Windows 和 Linux 环境中使用,因此修复越小越好。我宁愿不必为了在 Linux 中编译而重写数千行代码。谢谢!
【问题讨论】:
-
这可能与您如何定义静态成员有关,而不仅仅是声明它。如果你添加
inline会发生什么:inline static constexpr const char* s[] = {"one","two","three"};? -
@alterigel 从 C++17 开始,
static constexpr类成员变量隐含为inline。 -
OP,如果你使用
-std=c++17,它可以工作吗? -
很确定这是一个错误。 gcc 7.1+ 使用 c++17 编译良好。
-
如果您无法获得 C++17 支持,解决问题的一种方法是将静态数据成员替换为返回所需常量的静态成员函数(在类定义中定义) .类定义中定义的函数是隐式内联的(自 C++98 以来一直如此)。
标签: c++ gcc constexpr string-literals