Ill-formed C++0x code or compiler bug (GCC) ?

Discussion in 'C++' started by SG, Jan 28, 2011.

  1. SG

    SG Guest

    Hi!

    In the following C++0x code I tried to clone an object by using a
    clone member function (if it exists) and falling back on a copy
    constructor:

    #include <type_traits>

    struct use_copy_ctor {};
    struct prefer_clone_func : use_copy_ctor {};

    template<class T>
    auto clone(T const* ptr, prefer_clone_func)
    -> decltype(ptr->clone())
    { return ptr->clone(); }

    template<class T>
    auto clone(T const* ptr, use_copy_ctor)
    -> decltype(new T(*ptr))
    { return new T(*ptr); }

    struct abc {
    virtual ~abc() {}
    virtual abc* clone() const =0;
    };

    struct derived : abc
    {
    derived* clone() const { return new derived(*this); }
    };

    int main()
    {
    derived d;
    abc* p = &d;
    abc* q = clone(p,prefer_clone_func());
    delete q;
    }

    The idea is to use auto...->decltype(expr) to weed out ill-formed
    expressions as part of the template argument deduction (SFINAE) and to
    resolve a possible ambiguity between both clone function templates via
    partial ordering w.r.t. the second function parameter.

    Unfortunately, GCC 4.5.1 doesn't accept this program:

    test.cpp: In function 'int main()':
    test.cpp:30:39: error: cannot allocate an object of abstract type
    'abc'
    test.cpp:16:12: note: because the following virtual functions are
    pure within 'abc':
    test.cpp:18:16: note: virtual abc* abc::clone() const
    test.cpp:30:39: error: cannot allocate an object of abstract type
    'abc'
    test.cpp:16:12: note: since type 'abc' has pure virtual functions

    Now, the question is, is this a compiler bug or was I wrong to assume
    that SFINAE applies here?

    Cheers!
    SG
    SG, Jan 28, 2011
    #1
    1. Advertising

  2. SG

    SG Guest

    On 28 Jan., 11:36, SG wrote:
    >
    > In the following C++0x code I tried to clone an object by using a
    > clone member function (if it exists) and fall back on a copy
    > constructor:
    >
    > [...]
    >
    > Unfortunately, GCC 4.5.1 doesn't accept this program:
    >
    > [...]
    >
    > Now, the question is, is this a compiler bug or was I wrong to assume
    > that SFINAE applies here?


    I convinced myself that this is another case where GCC ignores the
    "NAE" in SFINAE in combination with templates and decltype and filed a
    bug report:

    http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47513

    Cheers!
    SG
    SG, Jan 28, 2011
    #2
    1. Advertising

  3. SG

    Marc Guest

    SG wrote:

    > In the following C++0x code I tried to clone an object by using a
    > clone member function (if it exists) and falling back on a copy
    > constructor:
    >
    > #include <type_traits>


    What for?

    > struct use_copy_ctor {};
    > struct prefer_clone_func : use_copy_ctor {};
    >
    > template<class T>
    > auto clone(T const* ptr, prefer_clone_func)
    > -> decltype(ptr->clone())
    > { return ptr->clone(); }
    >
    > template<class T>
    > auto clone(T const* ptr, use_copy_ctor)
    > -> decltype(new T(*ptr))
    > { return new T(*ptr); }
    >
    > struct abc {
    > virtual ~abc() {}
    > virtual abc* clone() const =0;
    > };
    >
    > struct derived : abc
    > {
    > derived* clone() const { return new derived(*this); }
    > };
    >
    > int main()
    > {
    > derived d;
    > abc* p = &d;
    > abc* q = clone(p,prefer_clone_func());
    > delete q;
    > }
    >
    > The idea is to use auto...->decltype(expr) to weed out ill-formed
    > expressions as part of the template argument deduction (SFINAE) and to
    > resolve a possible ambiguity between both clone function templates via
    > partial ordering w.r.t. the second function parameter.
    >
    > Unfortunately, GCC 4.5.1 doesn't accept this program:


    clang++ accepts it. It gained a lot of C++0x features last week, now
    it is just missing a library so we can start playing with it... (it
    can't handle the C++0x parts of libstdc++ and libc++ only works on
    Mac)
    Marc, Jan 28, 2011
    #3
  4. SG

    SG Guest

    On 28 Jan., 15:39, Marc wrote:
    > SG  wrote:
    > > In the following C++0x code I tried to clone an object by using a
    > > clone member function (if it exists) and falling back on a copy
    > > constructor:

    >
    > >    #include <type_traits>

    >
    > What for?


    Nothing, actually. It's a relict from previous versions. I removed
    this line before submitting the bug report. Initially, I used
    enable_if in combination with is_constructible<T,T const&>::value but
    libstdc++'s current implementation of is_constructible also "chokes"
    on abstract class types. I guess this is due to the same SFINAE<-
    >decltype issue I ran into (assuming is_constructible was implemented

    in terms of SFINAE+decltype).

    > clang++ accepts it. It gained a lot of C++0x features last week,


    Great!

    > now it is just missing a library so we can start playing with it...
    > (it can't handle the C++0x parts of libstdc++
    > and libc++ only works on Mac)


    Huh. I wouldn't have expected that.

    Cheers!
    SG
    SG, Jan 28, 2011
    #4
  5. SG

    Dilip Guest

    On Jan 28, 5:36 am, SG <> wrote:
    > Hi!
    >
    > In the following C++0x code I tried to clone an object by using a
    > clone member function (if it exists) and falling back on a copy
    > constructor:
    >
    >    #include <type_traits>
    >
    >    struct use_copy_ctor {};
    >    struct prefer_clone_func : use_copy_ctor {};
    >
    >    template<class T>
    >    auto clone(T const* ptr, prefer_clone_func)
    >    -> decltype(ptr->clone())
    >    { return ptr->clone(); }
    >
    >    template<class T>
    >    auto clone(T const* ptr, use_copy_ctor)
    >    -> decltype(new T(*ptr))
    >    { return new T(*ptr); }
    >
    >    struct abc {
    >      virtual ~abc() {}
    >      virtual abc* clone() const =0;
    >    };
    >
    >    struct derived : abc
    >    {
    >      derived* clone() const { return new derived(*this); }
    >    };
    >
    >    int main()
    >    {
    >      derived d;
    >      abc* p = &d;
    >      abc* q = clone(p,prefer_clone_func());
    >      delete q;
    >    }
    >
    > The idea is to use auto...->decltype(expr) to weed out ill-formed
    > expressions as part of the template argument deduction (SFINAE) and to
    > resolve a possible ambiguity between both clone function templates via
    > partial ordering w.r.t. the second function parameter.
    >
    > Unfortunately, GCC 4.5.1 doesn't accept this program:
    >
    > test.cpp: In function 'int main()':
    > test.cpp:30:39: error: cannot allocate an object of abstract type
    > 'abc'
    > test.cpp:16:12: note:   because the following virtual functions are
    > pure within 'abc':
    > test.cpp:18:16: note:        virtual abc* abc::clone() const
    > test.cpp:30:39: error: cannot allocate an object of abstract type
    > 'abc'
    > test.cpp:16:12: note:   since type 'abc' has pure virtual functions
    >
    > Now, the question is, is this a compiler bug or was I wrong to assume
    > that SFINAE applies here?
    >
    > Cheers!
    > SG


    VC++ 2010 fails with a *linker* error:

    error LNK2019: unresolved external symbol "public: __thiscall
    abc::abc(void)" (??0abc@@QAE@XZ) referenced in function "public:
    __thiscall derived::derived(void)" (??0derived@@QAE@XZ)
    Dilip, Jan 28, 2011
    #5
  6. SG

    SG Guest

    On 28 Jan., 20:19, Dilip wrote:
    > On Jan 28, 5:36 am, SG wrote:
    >
    > >    struct use_copy_ctor {};
    > >    struct prefer_clone_func : use_copy_ctor {};
    > >
    > >    template<class T>
    > >    auto clone(T const* ptr, prefer_clone_func)
    > >    -> decltype(ptr->clone())
    > >    { return ptr->clone(); }
    > >
    > >    template<class T>
    > >    auto clone(T const* ptr, use_copy_ctor)
    > >    -> decltype(new T(*ptr))
    > >    { return new T(*ptr); }
    > >
    > >    struct abc {
    > >      virtual ~abc() {}
    > >      virtual abc* clone() const =0;
    > >    };
    > >
    > >    struct derived : abc
    > >    {
    > >      derived* clone() const { return new derived(*this); }
    > >    };
    > >
    > >    int main()
    > >    {
    > >      derived d;
    > >      abc* p = &d;
    > >      abc* q = clone(p,prefer_clone_func());
    > >      delete q;
    > >    }

    >
    > VC++ 2010 fails with a *linker* error:
    >
    > error LNK2019: unresolved external symbol "public: __thiscall
    > abc::abc(void)" (??0abc@@QAE@XZ) referenced in function "public:
    > __thiscall derived::derived(void)" (??0derived@@QAE@XZ)


    That's weird. Looks like VC++ forgot to emit the definition of the
    "compiler-generated" default constructor of abc.
    SG, Jan 29, 2011
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    3,039
  2. Ill-formed program

    , Dec 4, 2008, in forum: C++
    Replies:
    1
    Views:
    410
  3. Johannes Schaub (litb)

    Is this using-declaration ill-formed?

    Johannes Schaub (litb), Aug 16, 2010, in forum: C++
    Replies:
    6
    Views:
    339
    James Kanze
    Aug 17, 2010
  4. m0shbear
    Replies:
    11
    Views:
    626
    m0shbear
    Jan 30, 2011
  5. K. Frank
    Replies:
    1
    Views:
    340
    K. Frank
    Nov 6, 2011
Loading...

Share This Page