【问题标题】:C++ template specialization problemC++模板特化问题
【发布时间】:2009-05-26 12:58:09
【问题描述】:

我需要一个 C++ 模板,给定一个类型和该类型的对象,它可以根据类型是否为整数做出决定,同时能够访问实际对象。我试过这个

template <typename T, T &N>
struct C {
    enum { Value = 0 };
};

template <int &N>
struct C<int, N> {
    enum { Value = N };
};

但它不起作用。有什么办法可以达到类似的效果吗?

编辑

我试图实现的是这样的,这将在编译时发生:

if (type is int) {
    return IntWrapper<int_value>
else {
    return type
}

您实际上可以在模板实例化中传递指向对象的指针或引用,如下所示:

struct X {
    static const int Value = 5;
};

template <X *x>
struct C {
    static const int Value = (*x).Value; 
};

X x;

std::cout << C<&x>::Value << std::endl; // prints 5

但显然所有这些都是通过推断x 的类型来初始化模板,并且x 也需要全局声明。我正在尝试做的事情没有用,我认为这在编译时毕竟是不可能的。

【问题讨论】:

  • 听起来你需要一个函数模板,因为类模板要求你明确指定模板类型参数。您能否发布一个使用示例来说明您要做什么?
  • @j_random_hacker:您可以将模板留空并拥有一个专门的类...您不必指定模板类型。

标签: c++ templates metaprogramming


【解决方案1】:

您尝试做的不是有效的 C++ 模板。您不能使用任意对象作为模板参数,您只能使用类型、整数文字以及在某些特殊情况下的字符串文字。

【讨论】:

  • 不知道为什么有人对你投了反对票,但我希望更多的信息能帮助你登上榜首......
【解决方案2】:

除非我误解了你,否则你想要的都是不可能的。在您的示例中,您显示了指针模板参数的无效使用。

template <X *x>
struct C {
    static const int Value = (*x).Value; 
};

这是无效的,因为(*x).Value 必须是一个常量表达式才能初始化Value。当然,X 类中的 Value 在用作 X::Value 时可以用作常量表达式。但是这一次,它不是因为它涉及一个指针(引用在常量表达式中同样无效)。

总而言之,你不能这样做:

Magic<T, someT>::type

如果 T 不是 int,则期望 ::type 为 T,否则为 IntWrapper&lt;someT&gt;,因为 T 只能是枚举、整数、指针或引用类型。在后两种情况下,您将无法获得指针所指向或在编译时引用所引用的任何内容的“值”。 如果您对此感到满意,那么解决您的问题很容易,我不会向您展示如何(我怀疑您已经知道如何)。

我认为你已经把自己逼入了这样一种境地,即按照既定的规则来解决你的问题变得不可能。当事情仍然允许解决问题时,退回一些步骤并向我们展示您正在尝试解决的真实问题。

【讨论】:

    【解决方案3】:

    也许一个简单的重载模板方法适用于您的情况?

    template<typename T>
    void doSomething(const T& x)
    {
        // ...
    }
    void doSomething(int x)
    {
        // ...
    }
    

    【讨论】:

      【解决方案4】:

      其他帖子的补充:您不再需要使用enum {}-hack:

      template<typename T, int val>
      struct Test {
          static const int Value = 0;
      };
      
      template <int val>
      struct Test<int, val> {
          static const int Value = val;
      };
      
      
      int main(int argc,char *argv[]) {
          const int v = Test<int,1>::Value;
      }
      

      【讨论】:

        【解决方案5】:
        
        template <typename T> struct A
        {
            enum { Value = false };
        };
        template <> struct A<int>
        {
            enum { Value = true };
        };
        

        那么这个怎么样:

        
        template <typename T> struct A
        {
            T value_;
            A() : value() {}
            enum { is_int = false };
        };
        template <> struct A<int>
        {
            int value_;
            explicit A( int v ) : value_( v ) {}
            enum { is_int = true };
        };
        

        【讨论】:

        • 这可行,但如果它是整数,我还需要实际值。
        【解决方案6】:

        我需要一个 C++ 模板,给定一个 类型和该类型的对象,它 可以根据是否 类型是否为整数,而 能够访问实际 对象。

        您可以根据类型是否为整数来做出决定,问题是不可能用任何类型的对象声明模板。所以关于如何判断一个类型是否为整数的问题是没有实际意义的。

        请注意,在所有答案中,您的原始模板都被巧妙地更改为

        template < typename T, int >
        class C {};
        

        而不是你的

        template< typename T, T >
        class C {};
        

        虽然C&lt;int, 5&gt; 是一个完全有效的声明,但对于任意类型的 T 则不是这种情况,例如C&lt;float, 5.&gt; 将给出编译器错误。

        你能准确地发布你想要实现的目标吗?

        为了记录,如果第二个模板参数始终是int,并且如果类型是整数类型,您只想获取它的值,否则为 0,您可以这样做:

        #include <limits>
        
        template< typename T, int N >
        class C {
            static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0;
        };
        

        【讨论】:

          【解决方案7】:

          你可以这样做:

          template<typename T, int val>
          struct Test
          {
              enum {Value = 0};
          };
          
          template <int val>
          struct Test<int, val>
          {
              enum {Value = val};
          };
          
          
          
          
          int main(int argc,char *argv[])
          {
              int v = Test<int,1>::Value;
          }  
          

          【讨论】:

            【解决方案8】:

            对您的代码进行简单修复 - 松开参考:

            template <typename T, T N>
            struct C {
                enum { Value = 0 };
            };
            
            template <int N>
            struct C<int, N> {
                enum { Value = N };
            };
            

            在模板参数中使用引用无论如何都是没有意义的,因为您实际上并没有在任何地方传递参数。

            【讨论】:

            • 这几乎只适用于整数。用浮点数试试。
            【解决方案9】:

            查看 Alexandrescu 的 Modern C++ Design。我相信第 2 章有一个正确的例子来说明你想要做什么。

            【讨论】:

              【解决方案10】:

              Template specialization可以这样实现(代码取自www.cplusplus.com):

              // template specialization
              #include <iostream>
              using namespace std;
              
              // class template:
              template <class T>
              class mycontainer {
                  T element;
                public:
                  mycontainer (T arg) {element=arg;}
                  T increase () {return ++element;}
              };
              
              // class template specialization:
              template <>
              class mycontainer <char> {
                  char element;
                public:
                  mycontainer (char arg) {element=arg;}
                  char uppercase ()
                  {
                    if ((element>='a')&&(element<='z'))
                    element+='A'-'a';
                    return element;
                  }
              };
              
              int main () {
                mycontainer<int> myint (7);
                mycontainer<char> mychar ('j');
                cout << myint.increase() << endl;
                cout << mychar.uppercase() << endl;
                return 0;
              }
              

              在您的情况下,您必须将 char 替换为类模板专业化中所需的内容。现在,我不太确定您要完成什么,但我希望上面的示例能够很好地指示您如何进行模板专业化。

              【讨论】:

                【解决方案11】:

                我试图实现的是这样的,这将在编译时发生:

                if (type is int) {
                    return IntWrapper<int_value>
                else {
                    return type
                }
                

                我不确定您为什么不使用 IntWrapper。如果它是 int,从哪里需要将编译时整数常量包装到 IntWrapper 中?

                否则,您似乎在尝试使用仅在运行时可用的数据来实例化模板。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-03-25
                  • 1970-01-01
                  相关资源
                  最近更新 更多