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

时间:2022-09-23 21:24:08

In C# I can write something like this:

在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);

    }

I intend to write a dictionary like template class in C++, I'd like the dict to return the default value (zero out) of the generic TVal type if the given key not be found. In C# the default(T) construct comes to rescue, while in C++ I'm not sure what is the appropriate way to do the same thing.

我打算在c++中编写一个类似于template类的字典,我希望如果找不到给定的键,我可以用dict词来返回泛型TVal类型的默认值(0 out)。在c#中,默认的(T)构造被拯救了,而在c++中,我不确定做同样的事情的合适方式是什么。

I've tried T obj = {} and T* obj = {} with gcc4.7, it works well. I'm just not so sure if it is the syntax defined by the language specification, if this kinda code will be portable cross compilers and platforms. Please help me with my doudt! Thanks in advance!

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

PS:

PS:

~~~~~~~~~~

~ ~ ~ ~ ~ ~ ~ ~ ~ ~

To make sure the template get the default(zero out) value of ANY type, even of those that don't have callable default ctor, I employed following mechanism (inspired by avakar's answer):

为了确保模板获得任何类型的默认值(0 out),即使是那些没有可调用的默认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
}

It looks ugly, but shouldn't cause any trouble, after all a zeroed out object is just a chunk of blank memory. Am I wrong?

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

4 个解决方案

#1


19  

In C++ there is no something like default keyword in C#. Since initialization by default constructor of value of class-type will be failed, if default constructor is private. In C#, if default constructor is private, value of class-type will be initialized to null, since class-type is reference-type.

在c++中,c#中没有默认的关键字。如果默认构造函数是私有的,那么类类型值默认构造函数的初始化将会失败。在c#中,如果默认构造函数是私有的,那么类类型的值将被初始化为null,因为类类型是引用类型。

Initialition by {} is defined by language specification. It's C++11. In C++03 you should use

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

T obj = T();

As pointed by bames53 in comment, when you want to initialize T* you should use

正如bames53在注释中指出的,当您想初始化T*时,应该使用

before C++11.

在c++ 11。

T* obj = 0;

or

T* obj = NULL;

in C++11.

在c++中11。

T* obj = {};

or

T* obj = nullptr;

#2


4  

Taken literaly from "The C++ Programming Language, Third Edition by Bjarne Stroustrup":

摘自《c++编程语言,Bjarne Stroustrup第三版》:

BEGIN QUOTE

开始报价

4.9.5 Initialization [dcl.init]

4.9.5初始化(dcl.init)

If an initializer is specified for an object, that initializer determines the initial value of an object. If no initializer is specified, a global (§4.9.4), namespace (§8.2), or local static object (§7.1.2, §10.2.4) (collectively called static objects) is initialized to 0 of the appropriate type. For example:

如果为对象指定了初始化器,该初始化器将确定对象的初始值。如果没有指定初始值设定项,全球(§4.9.4),名称空间(§8.2),或局部静态对象(§7.1.2,§10.2.4)(统称为静态对象)被初始化为0适当的类型。例如:

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

Local variables (sometimes called automatic objects) and objects created on the free store (sometimes called dynamic objects or heap objects) are not initialized by default. For example:

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

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

Members of arrays and structures are default initialized or not depending on whether the array or structure is static. User-defined types may have default initialization defined (§10.4.2).

数组和结构的成员是默认初始化的,这取决于数组或结构是静态的。用户定义类型可以定义默认初始化(§10.4.2)。

More complicated objects require more than one value as an initializer. This is handled by initializer lists delimited by { and } for C-style initialization of arrays (§5.2.1) and structures (§5.7).

更复杂的对象需要一个以上的值作为初始化器。这是由初始化器列表分隔为{和} c风格的初始化的数组(§5.2.1)和结构(§5.7)。

For user-defined types with constructors, function-style argument lists are used (§2.5.2, §10.2.3). Note that an empty pair of parentheses () in a declaration always means ‘‘function’’ (§7.1). For example:

用户定义类型的构造函数,function-style使用参数列表(§2.5.2,§10.2.3)。注意,一个空的一对括号()在一个声明总是意味着“功能”(§7.1)。例如:

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

END QUOTE

"

So, you can get the default value of any type form a static object of that type:

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

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

#3


3  

ForEveR's answer will not work if T doesn't have a copy constructor. In C++03, there is no way to zero-initialize a variable that is both generic and elegant. All that's left is the following trick.

如果T没有复制构造函数,则ForEveR的答案将不起作用。在c++ 03中,无法对泛型和优雅的变量进行零初始化。剩下的就是下面的技巧了。

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

Here, temp[0] is zero-initialized and then bound to obj. No copy constructors are needed.

这里,temp[0]是零初始化的,然后绑定到obj。不需要复制构造函数。

#4


1  

Create your own default keyword:

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

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

default_t const default = default_t();

Use it like:

使用它:

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

Or with a slight semantic variation:

或者有轻微的语义变化:

default_t const empty = default_t();

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

  return empty;
}

#1


19  

In C++ there is no something like default keyword in C#. Since initialization by default constructor of value of class-type will be failed, if default constructor is private. In C#, if default constructor is private, value of class-type will be initialized to null, since class-type is reference-type.

在c++中,c#中没有默认的关键字。如果默认构造函数是私有的,那么类类型值默认构造函数的初始化将会失败。在c#中,如果默认构造函数是私有的,那么类类型的值将被初始化为null,因为类类型是引用类型。

Initialition by {} is defined by language specification. It's C++11. In C++03 you should use

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

T obj = T();

As pointed by bames53 in comment, when you want to initialize T* you should use

正如bames53在注释中指出的,当您想初始化T*时,应该使用

before C++11.

在c++ 11。

T* obj = 0;

or

T* obj = NULL;

in C++11.

在c++中11。

T* obj = {};

or

T* obj = nullptr;

#2


4  

Taken literaly from "The C++ Programming Language, Third Edition by Bjarne Stroustrup":

摘自《c++编程语言,Bjarne Stroustrup第三版》:

BEGIN QUOTE

开始报价

4.9.5 Initialization [dcl.init]

4.9.5初始化(dcl.init)

If an initializer is specified for an object, that initializer determines the initial value of an object. If no initializer is specified, a global (§4.9.4), namespace (§8.2), or local static object (§7.1.2, §10.2.4) (collectively called static objects) is initialized to 0 of the appropriate type. For example:

如果为对象指定了初始化器,该初始化器将确定对象的初始值。如果没有指定初始值设定项,全球(§4.9.4),名称空间(§8.2),或局部静态对象(§7.1.2,§10.2.4)(统称为静态对象)被初始化为0适当的类型。例如:

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

Local variables (sometimes called automatic objects) and objects created on the free store (sometimes called dynamic objects or heap objects) are not initialized by default. For example:

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

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

Members of arrays and structures are default initialized or not depending on whether the array or structure is static. User-defined types may have default initialization defined (§10.4.2).

数组和结构的成员是默认初始化的,这取决于数组或结构是静态的。用户定义类型可以定义默认初始化(§10.4.2)。

More complicated objects require more than one value as an initializer. This is handled by initializer lists delimited by { and } for C-style initialization of arrays (§5.2.1) and structures (§5.7).

更复杂的对象需要一个以上的值作为初始化器。这是由初始化器列表分隔为{和} c风格的初始化的数组(§5.2.1)和结构(§5.7)。

For user-defined types with constructors, function-style argument lists are used (§2.5.2, §10.2.3). Note that an empty pair of parentheses () in a declaration always means ‘‘function’’ (§7.1). For example:

用户定义类型的构造函数,function-style使用参数列表(§2.5.2,§10.2.3)。注意,一个空的一对括号()在一个声明总是意味着“功能”(§7.1)。例如:

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

END QUOTE

"

So, you can get the default value of any type form a static object of that type:

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

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

#3


3  

ForEveR's answer will not work if T doesn't have a copy constructor. In C++03, there is no way to zero-initialize a variable that is both generic and elegant. All that's left is the following trick.

如果T没有复制构造函数,则ForEveR的答案将不起作用。在c++ 03中,无法对泛型和优雅的变量进行零初始化。剩下的就是下面的技巧了。

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

Here, temp[0] is zero-initialized and then bound to obj. No copy constructors are needed.

这里,temp[0]是零初始化的,然后绑定到obj。不需要复制构造函数。

#4


1  

Create your own default keyword:

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

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

default_t const default = default_t();

Use it like:

使用它:

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

Or with a slight semantic variation:

或者有轻微的语义变化:

default_t const empty = default_t();

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

  return empty;
}