7
template < unsigned int i >
struct t {
  static const char *s;
};
template < unsigned int i >
const char* t<i>::s = ...;

ここで、 ...は "0 1 2 ... i-1" です。たとえば、 の場合は "0 1 2 3 4" ですi == 5

これは可能ですか?(実行時にこれを行うソリューションはありません!)

  • 好奇心から尋ねられた質問 (プリプロセッサ マクロ/定数でそれを行うのは簡単ですが、テンプレート パラメーターはどうですか)?
  • 意味は、コンパイル時に生成された文字列リテラルです。constこれは強制ではありませんが、文字列生成のために実行時に評価される関数を使用できることがわかりました。
4

8 に答える 8

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;
}
于 2010-11-04T20:29:38.563 に答える
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();

ところで、なぜ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";
于 2010-11-04T11:27:29.983 に答える
1

不可能。

テンプレートの展開は、コンパイラが知っている定数値しか処理できないコンパイル時に行われるためです。メモリ割り当てを伴う操作 (文字列の初期化など) は現時点では実行できず、実行時にのみ実行できます。

于 2010-11-04T11:37:54.193 に答える
1

あなたが提示しているコード、...

template < unsigned int i >
struct t {
  static const char *s;
};
static const char* t::s = ...;

・・・無効です。t::s外部リンケージが必要です。また、定義はテンプレート化する必要があります。

コードの直接的な問題を修正する...

template < unsigned int i >
struct T
{
  static const char * const s;
};

template< unsigned i >
const char* const T<i>::s = ...;

...その後、T<i>::s任意の文字列で初期化するのは簡単です。

したがって、コードのエラーをモジュロすると、答えは「はい、可能であるだけでなく、些細なことです」です。

しかし、なぜこのルーブ・ゴールドバーグの計画で些細なことを成し遂げたいのですか?

于 2010-11-04T11:51:33.837 に答える
1

可変個引数テンプレートで実行できると思いますテストするコンパイラはありませんが、これに沿ったものがうまくいくと思います。

template < char ... RHS,  unsigned int i> 
struct t { 
    static const char s[] = t<' ', char(i+'0'), RHS, i-1>::s;
}; 

template <char ... RHS > 
struct t<RHS, 0> { 
    static const char s[] = {'0', RHS, '\0'};
}; 

void main() {
    std::cout << t<5>::s; // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'}
}
于 2011-01-14T23:22:43.543 に答える
0

これは、テンプレートを使用して行うことはできません。しかし、 を使用してstringstream作成するのstringは簡単です。擬似コードは次のとおりです。

string makeit(int i)
{
    stringstream sstr;

    for (int x = 0; x < i-1; x++)
        put x and ' ' in sstr;
    put i in sstr;
    return sstr contents converted to string
}

の詳細についてstringstream は、こちらを参照してください

于 2010-11-04T11:44:44.937 に答える
0
//using lambda
#include <sstream>
template<size_t i372> struct T369 {
    static std::string s;
};
template<size_t i372> std::string T369<i372>::s = [](){std::stringstream ss; 
for (int j = 0; j < i372; j++) { ss << "," << j; }; return ss.str(); }();
于 2018-05-12T23:10:46.000 に答える