如何获取任何类型的默认值

时间:2012-09-27 06:41:00

标签: c++ templates

在C#中,我可以这样写:

    class AnyThing<T>
    {
        static public T Default = default(T);
    }

    static void Main ()
    {
        int i = AnyThing<int>.Default;
        Console.WriteLine (i==0);
        string s = AnyThing<string>.Default;
        Console.WriteLine (s == null);

    }

我打算在C ++中编写一个类似模板类的字典,如果找不到给定的密钥,我希望dict返回通用TVal类型的默认值(零)。在C#中,默认(T)构造来拯救,而在C ++中,我不确定做同样事情的适当方法是什么。

我用gcc4.7尝试了T obj = {}T* obj = {},效果很好。我只是不确定它是否是语言规范定义的语法,如果这种类型的代码将是可移植的交叉编译器和平台。我的doudt请帮帮我!提前谢谢!

PS:

~~~~~~~~~~

为了确保模板获得任何类型的默认(零输出)值,即使是那些没有可调用默认ctor的值,我采用了以下机制(受avakar的回答启发):

template<class T>
struct AnyThing
{
    static const T& Default ;
private:
    static const char temp[sizeof(T)];
};

template<class T> const char AnyThing<T>::temp[] = {};
template<class T> const T& AnyThing<T>::Default =  *(T*)temp;

struct st
{
    double data;
    st()=delete;
};

int main()
{
    cout << (int)AnyThing<char*>::Default<<endl;    //0
    cout << AnyThing<int>::Default<<endl;       //0
    cout <<AnyThing<st>::Default.data<<endl;        //0
}

它看起来很丑,但不应该造成任何麻烦,毕竟归零的对象只是一块空白内存。我错了吗?

4 个答案:

答案 0 :(得分:22)

在C ++中,C#中没有类似default关键字的内容。由于默认构造函数为private,因此默认情况下初始化类型的值构造函数将失败。在C#中,如果默认构造函数是私有的,则class-type的值将初始化为null,因为类类型为reference-type

{}的初始化由语言规范定义。这是C ++ 11。在C ++ 03中,您应该使用

T obj = T();

正如评论中 bames53 指出的那样,当你想初始化T*时,你应该使用

在C ++ 11之前。

T* obj = 0;

T* obj = NULL;

在C ++ 11中。

T* obj = {};

T* obj = nullptr;

答案 1 :(得分:5)

从Bjarne Stroustrup的“C ++编程语言,第三版”中汲取文字:

BEGIN QUOTE

4.9.5初始化[dcl.init]

如果为对象指定了初始化程序,则该初始值设定项确定对象的初始值。如果未指定初始化程序,则将全局(第4.9.4节),名称空间(第8.2节)或本地静态对象(第7.1.2节,第10.2.2节)(统称为静态对象)初始化为适当类型的0 。例如:

int a;  // means int a=0;
double d; // meands d=0;

默认情况下,不会初始化本地变量(有时称为自动对象)和在空闲存储上创建的对象(有时称为动态对象或堆对象)。例如:

void f()
{
   int x;   // x does not have a well-defined value
   // . . . 
}

数组和结构的成员是默认初始化的,具体取决于数组或结构是否为静态。用户定义的类型可能已定义默认初始化(第10.4.2节)。

更复杂的对象需要多个值作为初始化程序。这由由{和}分隔的初始化列表处理,用于数组的C风格初始化(第5.2.1节)和结构(第5.7节)。

对于带有构造函数的用户定义类型,使用函数式参数列表(§2.5.2,§10.2.3)。请注意,声明中的一对空括号()始终表示''function''(第7.1节)。例如:

int a[] = {1,2};    // array initializer
Point z(1,2);       // function-style initializer (initialization by constructor)
int f();            // function declaration

结束语录

因此,您可以从该类型的静态对象中获取任何类型的默认值:

static T defaultT; // `defaultT' has de default value of type T

答案 2 :(得分:3)

如果T没有复制构造函数,ForEveR的答案将无效。在C ++ 03中,无法对初始化和优雅的变量进行零初始化。剩下的就是以下技巧。

T temp[1] = {};
T & obj = temp[0];

此处,temp[0]为零初始化,然后绑定到obj。不需要复制构造函数。

答案 3 :(得分:2)

创建您自己的默认关键字:

class default_t
{
public:
  template<typename T>
  operator T() const { return T(); }
};

default_t const default = default_t();

使用它像:

int myInt = default;
vector<string> myVector = default;
shared_ptr<string> myPtr = default;

或者有轻微的语义变化:

default_t const empty = default_t();

vector<Persons> fetchPersons()
{
  if (Database::isConnected())
  {
    return Database::fetchPersons();
  }

  return empty;
}