3

我需要一个 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还需要全局声明。我正在尝试做的事情没有用,我认为这在编译时毕竟是不可能的。

4

11 回答 11

7

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

于 2009-05-26T13:09:49.363 回答
5

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

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

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

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

Magic<T, someT>::type

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

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

于 2009-05-26T19:15:14.697 回答
4

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

template<typename T>
void doSomething(const T& x)
{
    // ...
}
void doSomething(int x)
{
    // ...
}
于 2009-05-26T13:43:42.480 回答
3

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 };
};
于 2009-05-26T13:15:56.217 回答
3

其他帖子的补充:您不再需要使用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;
}
于 2009-05-26T13:24:10.863 回答
2

你可以这样做:

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;
}  
于 2009-05-26T13:20:38.127 回答
2

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

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

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

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

而不是你的

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

但是,虽然C<int, 5>是一个完全有效的声明,但对于任意类型 T 而言,情况并非如此,例如C<float, 5.>会给出编译器错误。

你能准确地发布你想要达到的目标吗?

并且作为记录,如果第二个模板参数始终是int,并且如果类型是整数类型,您只想获取它的值,否则为 0,您可以简单地执行以下操作:

#include <limits>

template< typename T, int N >
class C {
    static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0;
};
于 2009-05-26T14:23:50.977 回答
0

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

于 2009-05-26T15:38:43.947 回答
0

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

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

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

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

于 2009-05-26T13:35:31.590 回答
0

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

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

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

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

于 2009-09-08T21:29:46.237 回答
0

模板专业化可以这样实现(代码取自 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 替换为类模板专业化中所需的内容。现在,我不太确定您要完成什么,但我希望上面的示例能够很好地指示您如何进行模板专业化。

于 2009-09-08T21:05:27.983 回答