16

在 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# 中,default(T) 构造来拯救,而在 C++ 中,我不确定做同样事情的合适方法是什么。

我已经尝试过T obj = {}使用T* obj = {}gcc4.7,它运行良好。我只是不太确定它是否是语言规范定义的语法,这种代码是否是可移植的交叉编译器和平台。请帮我解决我的疑问!提前致谢!

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

5 回答 5

32

在 C++ 中,C# 中没有类似default关键字的东西。由于类类型值的默认构造函数初始化将失败,如果默认构造函数是private. 在 C# 中,如果默认构造函数是私有的,则 class-type 的值将被初始化为null,因为 class-type 是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;
于 2012-09-27T06:43:41.430 回答
8

取自“Bjarne Stroustrup 的第三版 C++ 编程语言”:

开始报价

4.9.5 初始化[dcl.init]

如果为对象指定了初始化程序,则该初始化程序确定对象的初始值。如果未指定初始化程序,则将全局(第 4.9.4 节)、命名空间(第 8.2 节)或本地静态对象(第 7.1.2 节、第 10.2.4 节)(统称为静态对象)初始化为适当类型的 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 节)。

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

对于具有构造函数的用户定义类型,使用函数式参数列表(第 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

结束报价

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

static T defaultT; // `defaultT' has de default value of type T
于 2012-09-27T07:03:19.190 回答
5

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

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;
}
于 2013-09-17T10:26:18.113 回答
3

T如果没有复制构造函数,ForEveR 的答案将不起作用。在 C++03 中,没有办法对既通用又优雅的变量进行零初始化。剩下的就是以下技巧。

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

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

于 2012-09-27T07:13:09.597 回答
0

以下是我从 C++20 开始的做法:

constexpr auto default_value(const auto& value) {
  return std::decay_t<decltype(value)>{};
}

int main() {
  static_assert(default_value(std::string_view{"foo"}) == std::string_view{});
  static_assert(default_value(123) == 0);
  static_assert(default_value(&main) == nullptr);
}

如果您已经拥有T它应该是的类型,std::decay_t<T>{}或者T{}您确定它不是引用/数组/ ...(因为它们没有默认值)。

于 2022-01-29T16:21:26.467 回答