如何获取任何类型的默认值
How to get the default value of any type
在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++中编写一个类似模板类的字典,如果找不到给定的键,我希望字典返回通用 TVal 类型的默认值(零出)。在 C# 中,default(T) 构造可以提供帮助,而在 C++ 中,我不确定执行相同操作的合适方法是什么。
我已经尝试过T obj = {}
并使用gcc4.7T* obj = {}
,它运行良好。我只是不太确定它是否是语言规范定义的语法,如果这种代码将是可移植的跨编译器和平台。请帮我做我的杜特!提前感谢!
附注:
~~~~~~~~~
为了确保模板获得 ANY 类型的默认(零输出)值,即使是那些没有可调用的默认 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
}
它看起来很丑,但应该不会造成任何麻烦,毕竟归零的对象只是一大块空白内存。我错了吗?
在C++中,C# 中没有类似default
关键字的东西。由于默认情况下初始化类类型的值构造函数将失败,如果默认构造函数为private
.在 C# 中,如果默认构造函数是私有的,则类类型的值将被初始化为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;
字面意思摘自"The C++ Programming Language, Third Edition by Bjarne Stroustrup":
开始报价
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
创建自己的默认关键字:
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;
}
如果 ForEveR 没有复制构造函数,T
的答案将不起作用。在 C++03 中,无法对既通用又优雅的变量进行零初始化。剩下的就是下面的技巧。
T temp[1] = {};
T & obj = temp[0];
在这里,temp[0]
初始化为零,然后绑定到obj
。不需要复制构造函数。
以下是我截至 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
的类型,如果您确定它不是引用/数组/...(因为这些没有默认值)。
在 C++ 11 上,我们可以使用type{}
进行初始化 (https://en.cppreference.com/w/cpp/language/initialization)
所以:
int x{};//will work
decltype(x){};//as well as this
它也可以用于默认参数
template<typename Prev,typename Param,int n>
struct Bond {
const Prev& parent;
const Param param;
constexpr Bond(const Param param=Param{}):parent(Prev{}),param(param) {}
constexpr Bond(const Prev& parent,const Param param):parent(parent),param(param) {}
};
- C++ 将 CIN 值存储到任何类型的数组中
- 对任何类型的元素数组进行排序
- 任何种类的分数 在任何类型的订单中
- C++ - 声明指向返回任何类型并获取任意数量参数的函数的指针
- 正则表达式以匹配数字的重复模式,后跟任何类型的分隔符?
- 检查模板中 nullptr 的函数指针,了解任何类型的可调用对象
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- 为自定义打印调试实现传递任何类型的变量
- 我的代码中是否有任何类型的错误,因为它没有给出正确的输出
- 如何在不给它任何类型(如整数)的情况下定义某物?
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- C++如何使虚拟函数返回任何类型的指针
- 任何类型的缓存机制
- 如何在C++中接收任何类型的函数参数并获取函数内传递变量的类型?
- 如何在C++变量中存储任何类型的函数
- 将任何类型的表达式放在 c++ 的初始化列表中在语法上是否正确?
- 第一次捕获捕获任何类型的
- C++包含任何类型的模板类对象的映射
- 接受对任何类型的可变引用的 Lambda
- 将任何类型转换为任何类型