4

While trying to answer this question with a lambda based "const block", I've come across the situation where clang++ and g++ disagree on code validity.

#include <iostream>
#include <type_traits>

struct noncopyable
{
    int a;
    const noncopyable& operator=(noncopyable&&) = delete;
    noncopyable(noncopyable&&) = delete;
    const noncopyable& operator=(const noncopyable&) = delete;
    noncopyable(const noncopyable&) = delete;
    ~noncopyable() = default;
};

void modify(noncopyable& a)
{
    a.a = 0;
}

int main()
{
    noncopyable a = { 25 }, b = { 42 };
    [&, &a = static_cast<const noncopyable&>(a)]{
        modify(b);
        //modify(a); // uncommenting this should fail the build
    }();
    std::cout << a.a << " " << b.a << "\n";
    // expected output 25 0
}

clang++ accepts the code, and displays the expected output, while g++ fails with the following error message:

a.cpp: In function ‘int main()’:
a.cpp:22:5: error: binding ‘const noncopyable’ to reference of type ‘noncopyable&’ discards qualifiers
     [&, &a = static_cast<const noncopyable&>(a)]{
     ^

clang++ -v is

clang version 3.7.0 (tags/RELEASE_370/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-redhat-linux/5.1.1
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.1.1
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-redhat-linux/5.1.1
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64

and g++ -v is

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.1.1/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 5.1.1 20150618 (Red Hat 5.1.1-4) (GCC) 

The options used to compile the code were:

-std=c++14 -Wall -Wextra -pedantic

Which compiler is right? g++ or clang++? (or, the third option, is the code invalid for yet another reason?)

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
  • what's the purpose of the static_cast? – billz Dec 05 '15 at 11:32
  • @billz to trigger compiler differences :D – M.M Dec 05 '15 at 11:34
  • @billz The `static_cast` is used to "constify" a value (see also [`as_const`](http://en.cppreference.com/w/cpp/utility/as_const) from C++17). The intended purpose of the code is to make a variable non-modifiable inside the block. – milleniumbug Dec 05 '15 at 11:43
  • Is `const_cast` not defined for this purpose? – Jean-Baptiste Yunès Dec 05 '15 at 11:48
  • @Jean-BaptisteYunès It can do that, but you shouldn't use it for that purpose, as it can also remove the const, which can be unsafe, and you should use the least powerful cast if you can. Also see the question I linked to for more information. – milleniumbug Dec 05 '15 at 12:00
  • `Apple LLVM version 7.0.0 (clang-700.1.76)` gives me `note: candidate function not viable: 1st argument ('const noncopyable') would lose const qualifier`. – Jean-Baptiste Yunès Dec 05 '15 at 12:09
  • 2
    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66735 – T.C. Dec 05 '15 at 12:09

0 Answers0