我想做这样的事情:
template<int N> char* foo() { // return a compile-time string containing N, equivalent to doing // ostringstream ostr; // ostr << N; // return ostr.str().c_str(); }
看起来boost MPL库可能允许这样做,但我真的不知道如何使用它来完成这个。这可能吗?
wyyhbhjk1#
首先,如果你通常在运行时知道这个数字,你可以很容易地构建相同的字符串,也就是说,如果你的程序中有12,你也可以有"12"。预处理器宏还可以给参数加上引号,因此可以编写:
12
"12"
#define STRINGIFICATOR(X) #X
这个,每当你写STRINGIFICATOR(2),它就会产生“2”。然而,实际上不用宏(使用编译时元编程)就可以完成,这并不简单,所以我不能给予确切的代码,但我可以给你一些想法:1.用要转换的数字写一个递归模板,这个模板会递归到基本情况,也就是数字小于10。1.在每次迭代中,可以将N%10数字转换为T.E.D.建议的字符,使用mpl::string构建附加该字符的编译时字符串 * 和 *。1.您最终将构建一个mpl::string,它具有静态的value()字符串。我花时间把它作为个人练习来实施。最后还不错:
STRINGIFICATOR(2)
mpl::string
value()
#include <iostream> #include <boost/mpl/string.hpp> using namespace boost; // Recursive case template <bool b, unsigned N> struct int_to_string2 { typedef typename mpl::push_back< typename int_to_string2< N < 10, N/10>::type , mpl::char_<'0' + N%10> >::type type; }; // Base case template <> struct int_to_string2<true,0> { typedef mpl::string<> type; }; template <unsigned N> struct int_to_string { typedef typename mpl::c_str<typename int_to_string2< N < 10 , N>::type>::type type; }; int main (void) { std::cout << int_to_string<1099>::type::value << std::endl; return 0; }
jmo0nnb32#
我知道这个问题已经有几年的历史了,但是我想要一个使用纯C++11的解决方案,没有boost依赖性。所以这里有一些代码(借鉴了this answer to a different question的思想):
/* IMPLEMENTATION */ /* calculate absolute value */ constexpr int abs_val (int x) { return x < 0 ? -x : x; } /* calculate number of digits needed, including minus sign */ constexpr int num_digits (int x) { return x < 0 ? 1 + num_digits (-x) : x < 10 ? 1 : 1 + num_digits (x / 10); } /* metaprogramming string type: each different string is a unique type */ template<char... args> struct metastring { const char data[sizeof... (args)] = {args...}; }; /* recursive number-printing template, general case (for three or more digits) */ template<int size, int x, char... args> struct numeric_builder { typedef typename numeric_builder<size - 1, x / 10, '0' + abs_val (x) % 10, args...>::type type; }; /* special case for two digits; minus sign is handled here */ template<int x, char... args> struct numeric_builder<2, x, args...> { typedef metastring<x < 0 ? '-' : '0' + x / 10, '0' + abs_val (x) % 10, args...> type; }; /* special case for one digit (positive numbers only) */ template<int x, char... args> struct numeric_builder<1, x, args...> { typedef metastring<'0' + x, args...> type; }; /* convenience wrapper for numeric_builder */ template<int x> class numeric_string { private: /* generate a unique string type representing this number */ typedef typename numeric_builder<num_digits (x), x, '\0'>::type type; /* declare a static string of that type (instantiated later at file scope) */ static constexpr type value {}; public: /* returns a pointer to the instantiated string */ static constexpr const char * get () { return value.data; } }; /* instantiate numeric_string::value as needed for different numbers */ template<int x> constexpr typename numeric_string<x>::type numeric_string<x>::value; /* SAMPLE USAGE */ #include <stdio.h> /* exponentiate a number, just for fun */ static constexpr int exponent (int x, int e) { return e ? x * exponent (x, e - 1) : 1; } /* test a few sample numbers */ static constexpr const char * five = numeric_string<5>::get (); static constexpr const char * one_ten = numeric_string<110>::get (); static constexpr const char * minus_thirty = numeric_string<-30>::get (); /* works for any constant integer, including constexpr calculations */ static constexpr const char * eight_cubed = numeric_string<exponent (8, 3)>::get (); int main (void) { printf ("five = %s\n", five); printf ("one ten = %s\n", one_ten); printf ("minus thirty = %s\n", minus_thirty); printf ("eight cubed = %s\n", eight_cubed); return 0; }
输出:
five = 5 one ten = 110 minus thirty = -30 eight cubed = 512
pxq42qpu3#
这可以用C++14来实现,不需要任何外部依赖。标准的关键增加是拥有非平凡的constexpr构造函数的能力,允许将功能包含在一个简单的类中。给定一个整数模板参数,构造函数可以执行整数到字符串的转换。它存储在一个成员字符缓冲区中,该缓冲区的大小由一个附加的constexpr函数确定。然后,用户定义的转换提供对缓冲区的访问:
constexpr
#include <cstdint> template<std::intmax_t N> class to_string_t { constexpr static auto buflen() noexcept { unsigned int len = N > 0 ? 1 : 2; for (auto n = N; n; len++, n /= 10); return len; } char buf[buflen()] = {}; public: constexpr to_string_t() noexcept { auto ptr = buf + buflen(); *--ptr = '\0'; if (N != 0) { for (auto n = N; n; n /= 10) *--ptr = "0123456789"[(N < 0 ? -1 : 1) * (n % 10)]; if (N < 0) *--ptr = '-'; } else { buf[0] = '0'; } } constexpr operator const char *() const { return buf; } };
最后,一个变量模板(C++14的另一个附加功能)简化了语法:
template<std::intmax_t N> constexpr to_string_t<N> to_string; puts(to_string<62017>); // prints "62017"
该功能可以被扩展以支持其他基数(例如十六进制)、宽字符类型和公共容器接口;我把这些打包到一个头文件中,放在GitHub上的tcsullivan/constexpr-to-string。在C++20中,这也可以扩展为支持浮点数。浮点文字需要一个容器类型,以前不能作为模板参数。具体实现见GitHub repo中的f_to_string.hpp头文件。
f_to_string.hpp
6vl6ewon4#
也许我错过了什么,但这应该是简单的:
#define NUM(x) #x
不幸的是,这不适用于非类型模板参数。
q3aa05255#
在你知道你永远不会有一个超出0..9范围的数字的情况下,我看到过这样一个技巧:return '0' + N;乍看之下,这是令人烦恼的限制,然而,我很惊讶有多少次这种情况成立。哦,我知道这返回了一个char而不是std::string,这是一个特性,string不是一个内置的语言类型,所以没有办法在编译时创建一个。
0..9
return '0' + N;
char
std::string
string
ni65a41a6#
另一个有用的选项:
template <int i, bool gTen> struct UintToStrImpl { UintToStrImpl<i / 10, (i > 99)> c; const char c0 = '0' + i % 10; }; template <int i> struct UintToStrImpl <i, false> { const char c0 = '0' + i; }; template <int i, bool sign> struct IntToStrImpl { UintToStrImpl<i, (i > 9)> num_; }; template <int i> struct IntToStrImpl <i, false> { const char sign = '-'; UintToStrImpl<-i, (-i > 9)> num_; }; template <int i> struct IntToStr { IntToStrImpl<i, (i >= 0)> num_; const char end = '\0'; const char* str = (char*)this; }; std::cout << IntToStr<-15450>().str;
6条答案
按热度按时间wyyhbhjk1#
首先,如果你通常在运行时知道这个数字,你可以很容易地构建相同的字符串,也就是说,如果你的程序中有
12
,你也可以有"12"
。预处理器宏还可以给参数加上引号,因此可以编写:
这个,每当你写
STRINGIFICATOR(2)
,它就会产生“2”。然而,实际上不用宏(使用编译时元编程)就可以完成,这并不简单,所以我不能给予确切的代码,但我可以给你一些想法:
1.用要转换的数字写一个递归模板,这个模板会递归到基本情况,也就是数字小于10。
1.在每次迭代中,可以将N%10数字转换为T.E.D.建议的字符,使用
mpl::string
构建附加该字符的编译时字符串 * 和 *。1.您最终将构建一个
mpl::string
,它具有静态的value()
字符串。我花时间把它作为个人练习来实施。最后还不错:
jmo0nnb32#
我知道这个问题已经有几年的历史了,但是我想要一个使用纯C++11的解决方案,没有boost依赖性。所以这里有一些代码(借鉴了this answer to a different question的思想):
输出:
pxq42qpu3#
这可以用C++14来实现,不需要任何外部依赖。标准的关键增加是拥有非平凡的
constexpr
构造函数的能力,允许将功能包含在一个简单的类中。给定一个整数模板参数,构造函数可以执行整数到字符串的转换。它存储在一个成员字符缓冲区中,该缓冲区的大小由一个附加的
constexpr
函数确定。然后,用户定义的转换提供对缓冲区的访问:最后,一个变量模板(C++14的另一个附加功能)简化了语法:
该功能可以被扩展以支持其他基数(例如十六进制)、宽字符类型和公共容器接口;我把这些打包到一个头文件中,放在GitHub上的tcsullivan/constexpr-to-string。
在C++20中,这也可以扩展为支持浮点数。浮点文字需要一个容器类型,以前不能作为模板参数。具体实现见GitHub repo中的
f_to_string.hpp
头文件。6vl6ewon4#
也许我错过了什么,但这应该是简单的:
不幸的是,这不适用于非类型模板参数。
q3aa05255#
在你知道你永远不会有一个超出
0..9
范围的数字的情况下,我看到过这样一个技巧:return '0' + N;
乍看之下,这是令人烦恼的限制,然而,我很惊讶有多少次这种情况成立。
哦,我知道这返回了一个
char
而不是std::string
,这是一个特性,string
不是一个内置的语言类型,所以没有办法在编译时创建一个。ni65a41a6#
另一个有用的选项: