考虑以下代码片段(godbolt):
#include <cstdio>
#include <string>
#include <string_view>
struct Option
{
std::string_view name;
constexpr Option( std::string_view const n ) noexcept : name{n} {}
};
template< std::size_t N >
class TransformedOption : public Option
{
public:
constexpr TransformedOption( std::string_view const nameStr ) :
Option{ { nameStorage_, N - 1 } }
{
for ( auto i = 0U; i < N; ++i )
{
if ( nameStr[ i ] == '_' ) { nameStorage_[ i ] = '-'; }
else { nameStorage_[ i ] = nameStr[ i ]; }
}
}
private:
char nameStorage_[ N ] = {};
};
template< std::size_t N >
constexpr TransformedOption< N > make( char const (&nameStr)[ N ] ) noexcept
{
return TransformedOption< N >{ nameStr };
}
int main()
{
/*constexpr*/ auto t = make( "abcd_efgh_ijkl_mnop_peqst" );
std::printf( "%s\n", t.name.data() );
return 0;
}
基本上,我想通过将每个
_
替换为 -
并确保最终的二进制文件仅包含转换后的字符串(而不是原始字符串)来执行编译时字符串转换。我尝试过 Clang 10.0.1、GCC 10.2 和 MSVC 19.24(请参见上面的 godbolt 链接)。以下是一些奇怪的事情:
- 如果在 main 中注释掉
constexpr
,那么 MSVC 将生成错误的代码(即字符串的运行时转换),但 GCC 和 clang 都会生成正确的代码(即转换后的字符串常量嵌入到汇编中)。 - 如果在 main 中没有注释掉
constexpr
,那么 MSVC 将生成正确的代码(即转换后的字符串常量嵌入到汇编中),但 GCC 和 clang 都无法编译代码,并指出t
没有被常量表达式初始化(请参见 godbolt)。最奇怪的是,GCC 的错误消息输出了转换后的字符串,并指出它不是常量表达式。
constexpr
关键字来实现函数的编译期计算,但如果在需要常量表达式的上下文中调用该函数,则无法使用。 - Nicol BolasOption
基类(并通过函数调用根据需要生成string_view
),代码在所有编译器上都可以正常工作。因此,在基类中可能会发生一些混淆编译器的事情。 - Nicol Bolas