【问题标题】:Template Meta-programming with Char Arrays as Parameters以字符数组为参数的模板元编程
【发布时间】:2010-10-17 05:48:01
【问题描述】:

我在 GCC 4.3.2 的 C++11 的半实现中使用 TMP,我想知道是否有办法以某种方式执行以下操作:

template <char x, char... c>
struct mystruct {
...
};

int main () {

   mystruct<"asdf">::go();

}

它显然不会让我那样做,而且我认为在编译时使用用户定义的文字来转换“asdf”字符串会很幸运,但 GCC 4.3 不支持用户- 定义的文字...

有什么建议吗?我宁愿不做 'a','s','d','f',因为这严重妨碍了我对这个项目的计划。

【问题讨论】:

    标签: c++ templates gcc c++11 metaprogramming


    【解决方案1】:

    我解决了一个类似的问题。我们需要为每个名称使用不同的类型

    template< const char* the_name >
    class A
    {
        public:
        const char* name( void )
        {
            return the_name;
        }
    };
    
    extern const char g_unique_name[]; // defined elsewhere
    typedef A<g_unique_name> A_unique;
    

    这将使您在编译时访问名称和唯一的实例化。但是,它不会让您在运行时访问单个字符。

    如果您想要单个字符访问,实现它的唯一方法是使用用户定义的文字。 C++0x 将被扩展以允许上面 main 函数中的语法,但它仍会将模板绑定到字符指针而不是编译时字符数组。

    【讨论】:

    • 这个:template&lt; const char* the_name &gt; 是非法的 c++。
    【解决方案2】:

    遗憾的是,您仍然必须将其拆分为单独的字符,例如:

    myTemplate<'s','t','r','i','n','g'>
    

    在我看来,这是对新标准的巨大疏忽。其他一些人同意了,并尝试在 GCC 中实现该行为,并取得了不错的效果。你可以找到那个帖子here。

    编辑:链接有一些奇怪的问题,所以从这里剪切和粘贴:

    http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/9b0edd169ba2ce3c

    【讨论】:

    • 我非常感谢该线程的链接。它完全涵盖了我想做的事情。
    • 显然可以执行以下操作:myTemplate<_s>,其中 _S 是构造 mpl 字符串的宏。有可配置的预定义最大字符串长度。请参阅此处的讨论:cpp-next.com/archive/2012/10/…
    【解决方案3】:

    试试这个:

    extern const char SOMESTRING[] = "stringhere"; //extern linkage required!
    
    template<const char * const STR>
    struct MyStruct
    {
      static std::string doThis() { return STR; }
    };
    
    
    
    MyStruct<SOMESTRING>   testObj; //ok!
    

    克里斯

    【讨论】:

    • 这没有回答问题,OP希望字符串作为可变参数模板,而不仅仅是将字符串用作模板参数的一种方式。
    【解决方案4】:

    最近在 Boost.MPL 中添加了一个“string”,允许写入:

    typedef mpl::string<'asdf'> asdf;
    typedef mpl::push_back<asdf, mpl::char_<'!'> >::type asdf_bang;
    
    BOOST_ASSERT(0 == std::strcmp(mpl::c_str<asdf_bang>::value, "asdf!"));
    

    请注意,上面显示的示例有点做作,因为必须拆分由超过 4 个字符组成的“字符串”。例如:

    typedef mpl::string<'hell','o wo','rld'> hello;
    

    【讨论】:

      【解决方案5】:

      在 C++11 中,无法在编译时将临时字符串存储在任何地方。所以我可以建议你这种方法: (这是速写的草图,但描述性很好)

      #include <stdio.h>
      
      template <char...>
      struct StringTuple;
      
      template <char TargHead>
      struct StringTuple<TargHead> {
          static constexpr char kSymbol = TargHead;
      
          static void print() {
              printf(kSymbol ? "%c\n" : "\n", kSymbol);
          }
      };
      
      template <char TargHead, char... TargTail>
      struct StringTuple<TargHead, TargTail...> {
          using Next = StringTuple<TargTail...>;
          static constexpr char kSymbol = TargHead;
      
          static void print() {
              if (kSymbol) {
                  printf("%c", kSymbol);
                  Next::print();
              } else {
                  printf("\n");
              }
          }
      };
      
      constexpr int length(char *string) {
          return (string[0] == 0) ? 1 : (length(string + 1) + 1);
      }
      
      constexpr char get(char *string, int i) {
          return i < length(string) ? string[i] : 0;
      }
      
      #define ST(string) \
          StringTuple< \
          get(string, 0), \
          get(string, 1), \
          get(string, 2), \
          get(string, 3), \
          get(string, 4), \
          get(string, 5), \
          get(string, 6), \
          get(string, 7), \
          get(string, 8), \
          get(string, 9), \
          get(string, 10), \
          get(string, 11), \
          get(string, 12), \
          get(string, 13), \
          get(string, 14), \
          get(string, 15), \
          get(string, 16), \
          get(string, 17), \
          get(string, 18), \
          get(string, 19), \
          get(string, 20), \
          get(string, 21), \
          get(string, 22), \
          get(string, 23), \
          get(string, 24), \
          get(string, 25), \
          get(string, 26), \
          get(string, 27), \
          get(string, 28), \
          get(string, 29), \
          get(string, 30), \
          get(string, 31), \
          get(string, 32), \
          get(string, 33), \
          get(string, 34), \
          get(string, 35), \
          get(string, 36), \
          get(string, 37), \
          get(string, 38), \
          get(string, 39), \
          get(string, 40), \
          get(string, 41), \
          get(string, 42) \
          >
      
      int main() {
          ST("Hello, compile-time world!")::print();
      }
      

      生成部分宏的bash代码:

      for i in `seq 0 42`; do echo "    get(string, $i), \\"; done
      

      您必须将大量数字(1000 或更多)传递给此生成器以支持您的所有字符串,如果字符串超过此限制,您必须进行静态断言。


      我在自己的科学项目中使用此类生成的宏。我知道这看起来很乱,但它确实有效。生成宏的使用示例:

      #define PRINT(a) print(a);
      FOREACH_MACRO(PRINT, a, b, c) // print(a);print(b);print(c);
      

      我会尝试找到更漂亮的解决方案,但一开始我会使用这个。

      【讨论】:

        【解决方案6】:

        我不确定你想要实现什么,但是当你将“asdf”传递给模板时,它的类型是 char *,值是字符串的地址。因此,像概述的那样简单的方法将失败。如果不知道您首先要解决什么问题,就很难推荐任何东西。

        【讨论】:

        • 我想获取一个文字字符串,例如“asdf”,并将其传递到模板的参数列表中,就像 'a','s','d','f' 一样。
        【解决方案7】:

        你不能那样做。从标准中的 14.3.2 开始:

        非类型、非模板模板参数的模板参数应为以下之一:

        • 整数或枚举类型的整数常量表达式;或
        • 非类型模板参数的名称;或
        • 具有外部链接的对象或函数的地址,包括函数模板和函数模板ID 但不包括非静态类成员,表示为 & id-expression,其中 & 是可选的,如果名称指代
        • 一个函数或数组,或者如果相应的模板参数是一个引用;或
        • 计算结果为空指针值的常量表达式 (4.10);或
        • 计算结果为空成员指针值的常量表达式 (4.11);或
        • 指向成员的指针,如 5.3.1 中所述。
        • [ 注意:字符串文字 (2.13.4) 不满足任何这些类别的要求,因此不是可接受的模板参数

        【讨论】:

        • 在提议的 C++0x 标准中是可能的,但到目前为止我看到的唯一方法是使用用户定义的文字,我希望有一种不同的方法可以做到这一点支持用户定义文字的编译器。
        • 这就是我所说的用户定义的文字:stackoverflow.com/questions/537303/binary-literals/…
        • 哇,谢谢你的链接。我一直想要像 constexpr 这样的东西。
        【解决方案8】:

        引自新标准草案:

        14.3.2 模板非类型参数 [temp.arg.nontype]

        2 注意:字符串文字 (2.13.4) 不满足要求 这些类别中的任何一个,因此是 不是可接受的模板参数。

        示例:

        template<class T, char* p>
        class X 
        { 
        X(); 
        X(const char* q) { /... / } 
        }; 
        
        X<int, "Studebaker"> x1; // error: string literal as template-argument char p[] = "Vivisectionist";
        X<int,p> x2; // OK
        

        试试这个,但我不确定,因为http://gcc.gnu.org/gcc-4.3/cxx0x_status.html 没有说明这个功能。

        【讨论】:

          【解决方案9】:

          莫蒂错了。

          不幸的是,当前标准 (C++11) 不支持字符串参数的可变模板文字运算符,它只能用于数字。

          template <char... Args>
          operator ""_op();
          
          ...
          
          1212_op; // legal, calls operator ""_op<'1','2','1','2'>;
          "1212"_op; // illegal
          

          我不明白这个限制的目的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-06-08
            • 2017-07-21
            • 1970-01-01
            • 2018-11-11
            • 2020-06-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多