【问题标题】:Inconsistent use of const qualifier between declaration and definition声明和定义之间 const 限定符的使用不一致
【发布时间】:2013-12-18 13:03:46
【问题描述】:

我注意到在函数声明中存在的值参数上可能有const 限定符,然后在定义中被省略。这不会改变函数的签名。它实际上编译得很好。

我还注意到常规类和模板类之间的行为不同。在 GCC 和 Clang 中的处理方式也有所不同。

考虑以下代码:

template <typename T> struct A {
    void f(const int);
};

template <typename T> void A<T>::f(int x) {
    x = 0;
}

struct B {
    void f(const int);
};

void B::f(int x) {
    x = 0;
}

void f() {
    A<float> a;
    a.f(0);

    B b;
    b.f(0);
}

当我使用 GCC 编译时,我没有收到任何错误。使用 Clang 我得到:

test.cpp:10:7: error: read-only variable is not assignable
    x = 0;
    ~ ^
test.cpp:26:7: note: in instantiation of member function 'A<float>::f' requested here
    a.f(0);
      ^

GCC 在定义中优先使用限定符。 Clang 使用了声明并且仅用于模板类A

我的问题是:

  1. 这是由标准规定还是已定义此实现?
  2. 为什么常规类和模板类的行为不同?
  3. 为什么没有错误或至少警告const 限定符在声明和定义之间的使用不一致?
  4. 在任何情况下这可能有用吗?

更新:

根据 cmets,这似乎是一个 Clang 错误。我开了一个new ticket

更新:

错误已修复:

在 r203741 中修复

【问题讨论】:

  • 我认为错误是一个错误。
  • 顶级 const 限定符在语言级别被忽略。这意味着void foo(const int);void foo(int); 被认为是完全相同的声明。我怀疑clang在这里出错了。你用的是哪个版本?
  • @ShafikYaghmour 但在此示例中,模板参数与成员函数的参数无关。无论如何都是const int(即int)。
  • @juanchopanza 我明白你在说什么
  • @juanchopanza 我没有删除我的答案,在模板案例中我找不到任何使这个不同的东西。

标签: c++ gcc clang


【解决方案1】:

这种行为是由标准定义的,据我所知gcc 在这里是正确的,如果我们查看draft C++ standard 部分13.1 可重载声明 段落3 说:

[...]-仅在 const 和/或 volatile 存在或不存在方面不同的参数声明是等效的。也就是说,在确定声明、定义或调用哪个函数时,将忽略每个参数类型的 const 和 volatile 类型说明符。

并提供这个例子:

[ Example:
    typedef const int cInt;

    int f (int);
    int f (const int); // redeclaration of f(int)
    int f (int) { /* ... */ } // definition of f(int)
    int f (cInt) { /* ... */ } // error: redefinition of f(int)
—end example ]

以及一些详细说明这仅适用于最外层的 cv 限定符强调我的):

只有参数类型说明最外层的 const 和 volatile 类型说明符以这种方式被忽略; 隐藏在参数类型规范中的 const 和 volatile 类型说明符很重要,可用于区分重载的函数声明123 特别是,对于任何类型 T,“指向T”、“指向 const T 的指针”和“指向 volatile T 的指针”被认为是不同的参数类型,“对 T 的引用”、“对 const T 的引用”和“对 挥发性T。”

据我所知,这也适用于模板类中的模板函数以及 14.8 函数模板专业化 部分,特别是 14.8.3 重载分辨率 它说:

[...]完整的候选函数集包括所有综合声明和所有同名的非模板重载函数。除了在 13.3.3.144

中明确指出外,在重载决议的其余部分中,综合声明被视为与任何其他函数一样

【讨论】:

    【解决方案2】:

    这是一个错误,因为它会阻止以下合法代码:

    /* API declaration */
    void f(int);
    
    
    /* Implementation */
    void f(const int x) /* my business: x is my local var and I want it const */
    {
    }
    

    我不敢相信有人会不经意地编写代码来诊断这是一个问题。

    顺便说一句,不抱怨这一点的 GCC 曾经对这种情况发出警告。也许它仍然存在:

    void f(int func_ptr(void));
    
    void f(int (*func_ptr)(void))
    {
    }
    

    不过,这纯粹是一种风格上的不一致,没有任何目的。

    【讨论】:

    • 有趣,现在在gcc 中似乎可以正常工作了。我认为这些类型的角落很有趣,但我在信息安全领域花了很多时间,所以我一直在思考如何打破这些东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 2015-12-16
    相关资源
    最近更新 更多