如何在编译时标记默认参数的所有使用情况

时间:2018-11-07 16:29:25

标签: c++

我想找到所有使用构造函数的第二个默认参数的地方。签名看起来像这样:

enum Name {
    NONE = 0,
    BOB,
    LARRY
};

MyClass(const std::string& p1, int id = 0, name = NONE)
  : p1_(p1), id_(id), name_(name)
{ }

我有兴趣查找所有使用name缺省值的地方。即,所有未明确提供名称值的呼叫站点。我不关心在哪里明确提供NONE,仅在构造函数中没有提供名称的地方。

这让我震惊,因为它应该在编译时就可以发现,因此,我可以使用编译器来提醒我。

我最初的想法是将NONE删除为默认值,然后编译并浏览警告。但是后来我意识到,它前面的参数id具有默认值,因此删除默认的= NONE作为名称将不会编译,因为在有参数的情况下,没有默认值就没有参数。

第二次尝试是添加一个名为DEFAULT_WAS_USED的新Name枚举值,将其设置为默认值,然后使用static_assert进行编译:

enum Name {
    NONE = 0,
    BOB,
    LARRY,
    DEFAULT_WAS_USED
};

MyClass(const std::string& p1, int id = 0, name = DEFAULT_WAS_USED)
  : p1_(p1), id_(id), name_(name)
{
    static_assert(name_ != DEFAULT_WAS_USED, "default name was used");
}

但是,尽管在编译时会严格知道使用名称DEFAULT_WAS_USED,因为我知道代码中的任何地方都不会使用值,而只会将其用作默认参数,但编译器并不知道情况,无法对此进行编译。

我是否有一种聪明的方法来使用编译器或链接器在使用默认参数的代码中查找所有位置?

我正在使用gcc 4.8。

3 个答案:

答案 0 :(得分:2)

您可以做的一件事是添加几个已删除的构造函数,并摆脱“主”构造函数中的默认参数。

struct MyClass
{
    MyClass(const std::string& p1) = delete;
    MyClass(const std::string& p1, int id)  = delete;
    MyClass(const std::string& p1, int id, Name name) : p1_(p1), id_(id), name_(name) {}
    std::string p1_;
    int id_;
    Name name_;
};

会出错

MyClass{"foo"};
MyClass{"foo", 10};

但不会出现错误

MyClass{"foo", 42, BOB};

答案 1 :(得分:2)

如果您想捕获使用name的默认值的地方,那么id也具有默认值并不重要:除非他们也使用了{{ 1}}的默认值,这是您无论如何都要抓住的情况。

因此只需去除两个默认值,然后观察火焰飞扬。

但是没有魔术标记,也没有切换到精确/自动执行您所要的内容的方法,

答案 2 :(得分:0)

您可能会创建过载:

MyClass(const std::string& p1, int id, Name name)
  : p1_(p1), id_(id), name_(name)
{}

MyClass(const std::string& p1, int id = 0) = delete; // Name no provided explicitly