c ++:从模板参数生成字符串文字

Tho*_*mas 6 c++ templates metaprogramming string-literals

template < unsigned int i >
struct t {
  static const char *s;
};
template < unsigned int i >
const char* t<i>::s = ...;
Run Code Online (Sandbox Code Playgroud)

其中 ...是"0 1 2 ... i-1",例如"0 1 2 3 4" i == 5.

这可能吗?(请不要在运行时做这个解决方案!)

  • 问题是出于好奇(用预处理器宏/常量做这件事很容易,但模板参数怎么样)?
  • 含义是:编译时生成的字符串文字.我现在看到const它不会强制执行此操作,但可以对字符串生成采用任何运行时评估函数.

Jon*_*Jon 6

这在技术上是可行的,它非常非常难看.这是一个为unsigned int生成字符串文字的示例.它还没有(还)创建一个"1 2 3 ... i-1"形式的字符串,但是我确信如果你愿意付出努力就有可能.

#include <iostream>
#include <string>
#include <limits>

///////////////////////////////////////////////////////////////////////////////
// exponentiation calculations
template <int accum, int base, int exp> struct POWER_CORE : POWER_CORE<accum * base, base, exp - 1>{};

template <int accum, int base>
struct POWER_CORE<accum, base, 0>
{
    enum : int { val = accum };
};

template <int base, int exp> struct POWER : POWER_CORE<1, base, exp>{};

///////////////////////////////////////////////////////////////////////////////
// # of digit calculations
template <int depth, unsigned int i> struct NUM_DIGITS_CORE : NUM_DIGITS_CORE<depth + 1, i / 10>{};

template <int depth>
struct NUM_DIGITS_CORE<depth, 0>
{
    enum : int { val = depth};
};

template <int i> struct NUM_DIGITS : NUM_DIGITS_CORE<0, i>{};

template <>
struct NUM_DIGITS<0>
{
    enum : int { val = 1 };
};

///////////////////////////////////////////////////////////////////////////////
// Convert digit to character (1 -> '1')
template <int i>
struct DIGIT_TO_CHAR
{
    enum : char{ val = i + 48 };
};

///////////////////////////////////////////////////////////////////////////////
// Find the digit at a given offset into a number of the form 0000000017
template <unsigned int i, int place> // place -> [0 .. 10]
struct DIGIT_AT
{
    enum : char{ val = (i / POWER<10, place>::val) % 10 };
};

struct NULL_CHAR
{
    enum : char{ val = '\0' };
};

///////////////////////////////////////////////////////////////////////////////
// Convert the digit at a given offset into a number of the form '0000000017' to a character
template <unsigned int i, int place> // place -> [0 .. 9]
    struct ALT_CHAR : DIGIT_TO_CHAR< DIGIT_AT<i, place>::val >{};

///////////////////////////////////////////////////////////////////////////////
// Convert the digit at a given offset into a number of the form '17' to a character

// Template description, with specialization to generate null characters for out of range offsets
template <unsigned int i, int offset, int numDigits, bool inRange>  
    struct OFFSET_CHAR_CORE_CHECKED{};
template <unsigned int i, int offset, int numDigits>                
    struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, false> : NULL_CHAR{};
template <unsigned int i, int offset, int numDigits>                
    struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, true>  : ALT_CHAR<i, (numDigits - offset) - 1 >{};

// Perform the range check and pass it on
template <unsigned int i, int offset, int numDigits>
    struct OFFSET_CHAR_CORE : OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, offset < numDigits>{};

// Calc the number of digits and pass it on
template <unsigned int i, int offset>
    struct OFFSET_CHAR : OFFSET_CHAR_CORE<i, offset, NUM_DIGITS<i>::val>{};

///////////////////////////////////////////////////////////////////////////////
// Integer to char* template. Works on unsigned ints.
template <unsigned int i>
struct IntToStr
{
    const static char str[];
};

template <unsigned int i>
const char IntToStr<i>::str[] = 
{
    OFFSET_CHAR<i, 0>::val,
    OFFSET_CHAR<i, 1>::val,
    OFFSET_CHAR<i, 2>::val,
    OFFSET_CHAR<i, 3>::val,
    OFFSET_CHAR<i, 4>::val,
    OFFSET_CHAR<i, 5>::val,
    OFFSET_CHAR<i, 6>::val,
    OFFSET_CHAR<i, 7>::val,
    OFFSET_CHAR<i, 8>::val,
    OFFSET_CHAR<i, 9>::val,
    NULL_CHAR::val
};


///////////////////////////////////////////////////////////////////////////////
// Tests
int _tmain(int argc, _TCHAR* argv[])
{
    std::wcout << IntToStr<17>::str << std::endl;
    std::wcout << IntToStr<173457>::str << std::endl;
    std::wcout << IntToStr< INT_MAX >::str << std::endl;
    std::wcout << IntToStr<0>::str << std::endl;
    std::wcout << IntToStr<1>::str << std::endl;
    std::wcout << IntToStr<-1>::str << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


BЈо*_*вић 3

不,但是这是可能的:

template < unsigned int i >
struct t {
  static std::string s;

  static std::string ConvertIntToString()
  {
    std::stringstream ss;
    ss << i;
    return ss.str();
  }
};

template< unsigned int i >
std::string t< i >::s = t<i>::ConvertIntToStr();
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你为什么使用 C 字符串?C++ 有 std::string 类,这是优越的。

编辑

我想你可以使用模板专业化:

template < unsigned int i >
struct t;

template <>
struct t<0>
{
  static const char * const s;
};
const char* const t<0>::s = "abc";

template <>
struct t<1>
{
  static const char * const s;
};
const char* const t<1>::s = "123";
Run Code Online (Sandbox Code Playgroud)