基于模板编译时间字符串生成器
Compile time string generator based on templates
我正在开发基于mfc 的GUI。其中一个控件允许标记语言 (XAML) 在其中呈现文本和图标,因此我正在大量使用它。所有控件的标记字符串几乎相同(一个表单中有 12 个),所以我想知道这是否是一种生成该字符串的函数的简单方法。
所以控件是预定义的,在执行过程中不会改变,我想在编译时生成这些字符串,就像直接输入然后编译一样。
我正在使用 boost::hana
,但我无法通过我尝试过的任何方式在模板中使用字符串文字。我知道由于编译时内存分配未知,无法在模板中直接使用字符串文字。
除了在结构中使用 extern
或 static
分配的经典技巧外,由于增加了语法复杂性,我不喜欢 C++17(或更低版本,但请不要使用 c++20) 来允许这个?
注意 - 一个额外的应该是在不使用宏的函数中直接格式化 int(使用 10 而不是“10”)。
接下来是代码,当然,它不会以当前形式编译:
#include <iostream>
#include <boost/hana/string.hpp>
namespace hana = boost::hana;
constexpr auto markup1()
{
return (BOOST_HANA_STRING(R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'><TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)") +
BOOST_HANA_STRING("USERS") +
BOOST_HANA_STRING(R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)") +
BOOST_HANA_STRING("User Management. Allows creation of administrators and users.") +
BOOST_HANA_STRING(R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')") +
BOOST_HANA_STRING("10") +
BOOST_HANA_STRING(R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
template <const char* header, const char* description, const char* image>
constexpr auto markup2()
{
return (BOOST_HANA_STRING(R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'><TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)") +
BOOST_HANA_STRING(header) +
BOOST_HANA_STRING(R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)") +
BOOST_HANA_STRING(description) +
BOOST_HANA_STRING(R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')") +
BOOST_HANA_STRING(image) +
BOOST_HANA_STRING(R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
int main()
{
std::string str1 { markup1() };
std::string str2 { markup2<"USERS", "User Management. Allows creation of administrators and users.", "10">() };
std::cout << std::boolalpha << (str1 == str2);
}
可直接访问 coliru:http://coliru.stacked-crooked.com/a/4a5bc326be33cb3e
将字符串文字直接作为模板参数传递是不合法的;但是,可以将字符串文字绑定到 constexpr
数组并改为(通过引用)传递:
template<auto const& header, auto const& description, auto const& image>
constexpr auto markup2() { ... }
int main() {
static constexpr char const h2[] = "USERS";
static constexpr char const d2[] = "User Management. Allows creation of administrators and users.";
static constexpr char const i2[] = "10";
std::string_view const str1{ markup1() },
str2{ markup2<h2, d2, i2>() };
return str1 == str2;
}
当然,在预先编写了一些样板之后,C++20 有多个选项可以使它更漂亮。
您可以将 HANA_STRING
作为“常规”(需要是模板)参数:
template <typename Header, typename Description, typename Image>
constexpr auto markup2(Header header, Description description, Image image)
{
return (BOOST_HANA_STRING(
R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'>
<TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)")
+ header
+ BOOST_HANA_STRING(
R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)")
+ description
+ BOOST_HANA_STRING(
R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')")
+ image
+ BOOST_HANA_STRING(
R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
调用类似于
std::string str2 { markup2(
BOOST_HANA_STRING("USERS"),
BOOST_HANA_STRING("User Management. Allows creation of administrators and users."),
BOOST_HANA_STRING("10")) };
我正在开发基于mfc 的GUI。其中一个控件允许标记语言 (XAML) 在其中呈现文本和图标,因此我正在大量使用它。所有控件的标记字符串几乎相同(一个表单中有 12 个),所以我想知道这是否是一种生成该字符串的函数的简单方法。
所以控件是预定义的,在执行过程中不会改变,我想在编译时生成这些字符串,就像直接输入然后编译一样。
我正在使用 boost::hana
,但我无法通过我尝试过的任何方式在模板中使用字符串文字。我知道由于编译时内存分配未知,无法在模板中直接使用字符串文字。
除了在结构中使用 extern
或 static
分配的经典技巧外,由于增加了语法复杂性,我不喜欢 C++17(或更低版本,但请不要使用 c++20) 来允许这个?
注意 - 一个额外的应该是在不使用宏的函数中直接格式化 int(使用 10 而不是“10”)。
接下来是代码,当然,它不会以当前形式编译:
#include <iostream>
#include <boost/hana/string.hpp>
namespace hana = boost::hana;
constexpr auto markup1()
{
return (BOOST_HANA_STRING(R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'><TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)") +
BOOST_HANA_STRING("USERS") +
BOOST_HANA_STRING(R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)") +
BOOST_HANA_STRING("User Management. Allows creation of administrators and users.") +
BOOST_HANA_STRING(R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')") +
BOOST_HANA_STRING("10") +
BOOST_HANA_STRING(R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
template <const char* header, const char* description, const char* image>
constexpr auto markup2()
{
return (BOOST_HANA_STRING(R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'><TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)") +
BOOST_HANA_STRING(header) +
BOOST_HANA_STRING(R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)") +
BOOST_HANA_STRING(description) +
BOOST_HANA_STRING(R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')") +
BOOST_HANA_STRING(image) +
BOOST_HANA_STRING(R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
int main()
{
std::string str1 { markup1() };
std::string str2 { markup2<"USERS", "User Management. Allows creation of administrators and users.", "10">() };
std::cout << std::boolalpha << (str1 == str2);
}
可直接访问 coliru:http://coliru.stacked-crooked.com/a/4a5bc326be33cb3e
将字符串文字直接作为模板参数传递是不合法的;但是,可以将字符串文字绑定到 constexpr
数组并改为(通过引用)传递:
template<auto const& header, auto const& description, auto const& image>
constexpr auto markup2() { ... }
int main() {
static constexpr char const h2[] = "USERS";
static constexpr char const d2[] = "User Management. Allows creation of administrators and users.";
static constexpr char const i2[] = "10";
std::string_view const str1{ markup1() },
str2{ markup2<h2, d2, i2>() };
return str1 == str2;
}
当然,在预先编写了一些样板之后,C++20 有多个选项可以使它更漂亮。
您可以将 HANA_STRING
作为“常规”(需要是模板)参数:
template <typename Header, typename Description, typename Image>
constexpr auto markup2(Header header, Description description, Image image)
{
return (BOOST_HANA_STRING(
R"(<Border Padding='4' BorderThickness='2' BorderBrush='#767676' Background='#e4ecf7'>
<StackPanel TextBlock.FontFamily='Tahoma'>
<Border Margin='4' Padding='4' Background='#FF212C'>
<TextBlock HorizontalAlignment='Center' Foreground='#ffffff' FontSize='24' FontWeight='Bold'>)")
+ header
+ BOOST_HANA_STRING(
R"(</TextBlock></Border>
<TextBlock Padding='9, 6, 30, 7' FontWeight='Bold' TextWrapping='Wrap'>)")
+ description
+ BOOST_HANA_STRING(
R"(</TextBlock>
<Border Height='1' Background='#9ebbdd'/>
<Border Height='1' Background='White'/>
<Image Source=')")
+ image
+ BOOST_HANA_STRING(
R"(' Margin='10' VerticalAlignment='Center'/>
</StackPanel>
</Border>)") ).c_str();
}
调用类似于
std::string str2 { markup2(
BOOST_HANA_STRING("USERS"),
BOOST_HANA_STRING("User Management. Allows creation of administrators and users."),
BOOST_HANA_STRING("10")) };