为啥我不能将类构造函数参数设置为默认值?

Posted

技术标签:

【中文标题】为啥我不能将类构造函数参数设置为默认值?【英文标题】:Why can't I set class constructor parameter to a default value?为什么我不能将类构造函数参数设置为默认值? 【发布时间】:2016-04-23 14:20:07 【问题描述】:
template<class KeyType, class ValueType, class Hash = std::hash<KeyType> >
class HashMap 
 public:
    Hash hasher;

    HashMap(Hash override_ = hasher) 
        hasher = override_;
    
;

这是我的代码。我期望发生的是,如果构造函数没有提供任何值,我将保留hasher 的默认值,否则将其更改为新值。我得到的是:invalid use of non-static data member 'hasher'。我已经想到我可以将hasher 替换为Hash() 作为默认值;但是如果我不需要默认的Hash 对象而是更复杂的东西怎么办?为什么我的第一次尝试没有编译?

【问题讨论】:

构造函数的默认参数在对象构造开始之前被解析,所以hasher在那个时候不会存在 一个好的解决方案是 2 个构造函数,另一个是 HashMap() 【参考方案1】:

您正在尝试将类的成员用作构造函数参数的默认值,而对象尚未创建。除非成员是静态的,否则这是行不通的。为了做你想做的事,你可以定义2个构造函数,这样:

#include <map>
template<class KeyType, class ValueType, class Hash = std::hash<KeyType> >
class HashMap 
public:
    Hash hasher;

    HashMap(Hash override_) 
        hasher = override_;
    
    HashMap() 
    
;

【讨论】:

我不明白的是为什么我不能这样使用它。我已经通过使用Hash() 作为默认值绕过了这个问题,所以我的问题更多是关于“为什么?”而不是“如何?”。 @Akiiino hasher此时还没有创建,要怎么使用呢? @Slava 但是如果它是static --- 当我第一次创建HashMap 时,它还没有创建,或者是吗? @Akiiino:如果成员是静态的,则在程序初始化时创建,不需要实例;在对象实例化时创建一个非静态成员。 @shrike 你确定是这样吗?由于我的类具有模板参数,并且具有不同模板参数的不同实例不共享它们的statics,因此似乎不太可能为每种可能的参数组合生成static 变量。【参考方案2】:

按照标准是禁止的。这在 C++03 标准的第 8.3.6 节中有详细说明。它基本上相当于任何不依赖于本地范围内任何内容的表达式,因此任何依赖于局部变量、函数参数或“this”的表达式都被排除在外。

【讨论】:

【参考方案3】:

好吧,你可以这样做:

template<class KeyType, class ValueType, class Hash = std::hash<KeyType> >
class HashMap 
 public:
    Hash hasher;

    HashMap(Hash override_ = ) : hasherstd::move(override_) 
;

如果没有提供,则调用默认构造函数。

就个人而言,我认为最好的选择是添加一个默认构造函数:

template<class KeyType, class ValueType, class Hash = std::hash<KeyType> >
class HashMap 
 public:
    Hash hasher;

    HashMap() = default;
    HashMap(Hash override_) : hasherstd::move(override_) 
;

【讨论】:

以上是关于为啥我不能将类构造函数参数设置为默认值?的主要内容,如果未能解决你的问题,请参考以下文章

默认构造函数,为啥我的类似乎有三个?当编译器将类视为结构时?

golang函数中的参数为啥不支持默认值

在JAVA中能给方法参数赋默认值吗

为啥 C++ 构造函数在继承中需要默认参数?

C++类-使用默认参数的构造函数

C++类-使用默认参数的构造函数