Problem trying to call copy constructor in base class which has a std::any constructor
Asked Answered
S

1

6

Consider the following code:

#include <any>

struct A {
    A();
    A(const A&) = default;
    explicit A(std::any value);
};

struct B: A {
    B() : A() { }
    B(const B& b) : A(b) {}
    explicit B(std::any value) : A(value) {}
};

The compiler reports the following error on compilation (using clang++-5 or higher):

In file included from <source>:2:
In file included from /opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:37:
In file included from /opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/new:40:
In file included from /opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/exception:143:
In file included from /opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/nested_exception.h:40:
In file included from /opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/move.h:54:
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/type_traits:149:31: error: no member named 'value' in 'std::is_copy_constructible<B>'
: public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type
                     ~~~~~^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:192:27: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<B>, std::__not_<std::is_constructible<B, const B &> >, std::__not_<std::__is_in_place_type<B> > >' requested here
          enable_if_t<__and_<is_copy_constructible<_Tp>,
                      ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:196:7: note: while substituting prior template arguments into non-type template parameter [with _ValueType = const B &, _Tp = B, _Mgr = std::any::_Manager_external<B>]
  any(_ValueType&& __value)
  ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/type_traits:973:28: note: while substituting deduced template arguments into function template 'any' [with _ValueType = const B &, _Tp = (no value), _Mgr = (no value), $3 = (no value)]
         = decltype(::new _Tp(declval<_Arg>()))>
                              ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/type_traits:974:24: note: in instantiation of default argument for '__test<B, const B &>' required here
  static true_type __test(int);
                   ^~~~~~~~~~~
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/type_traits:984:24: note: while substituting deduced template arguments into function template '__test' [with _Tp = B, _Arg = const B &, $2 = (no value)]
  typedef decltype(__test<_Tp, _Arg>(0)) type;
                   ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/type_traits:144:14: note: (skipping 9 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
: public conditional<_B1::value, _B2, _B1>::type
         ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:170:17: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<B>, std::is_constructible<B, const B &> >' requested here
  enable_if<__and_<is_copy_constructible<_Tp>,
            ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:175:5: note: in instantiation of template type alias '__any_constructible' requested here
using __any_constructible_t =
^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:181:56: note: in instantiation of template type alias '__any_constructible_t' requested here
          __any_constructible_t<_Tp, _ValueType&&> = true,
                                                   ^
/opt/compiler-explorer/gcc-7.3.0/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/any:183:7: note: while substituting prior template arguments into non-type template parameter [with _ValueType = const B &, _Tp = B, _Mgr = std::any::_Manager_external<B>]
  any(_ValueType&& __value)
  ^~~~~~~~~~~~~~~~~~~~~~~~~
<source>:63:23: note: while substituting deduced template arguments into function template 'any' [with _ValueType = const B &, _Tp = (no value), _Mgr = (no value), $3 = (no value), $4 = (no value)]
B(const B& b) : A(b) {       
                  ^
1 error generated.
Compiler returned: 1

Interestingly, it compiles in gcc-7.1 or higher.

Is the copy constructor for B calling the constructor of A instead of the copy constructor for A which is what I want to happen? If so, how do I make the B copy constructor work as I am intending it to do?

p.s. Here's a link to the online compiler I used for this https://godbolt.org/z/_22nuW.

Spineless answered 11/3, 2019 at 17:37 Comment(7)
@SombreroChicken I just verified that it does compile in gcc-7.1 or higher but not clang-6 or clang-7.Spineless
I took the liberty of reducing your example a bunch - in the future, try to remove as many of the irrelevant things to the problem as possible, it makes it easier to understand what's going on. In this case, the problem is with B's copy constructor, so C was completely irrelevant.Auvil
Actually you don't even need B: godbolt.org/z/Xc7mXMAuvil
Interesting: there's a circular issue where to see if the A(any) constructor is a viable function with an argument of type const A, the compiler evaluates the template constructor any(T&&), which includes a SFINAE check for is_copy_constructible, which involves an expression SFINAE on ::new A(declval<const A&>()), which means checking if constructor A(any) is viable... Same for B. I don't know how to work around this, though.Sarajane
Someone filed this as a bug for clang: bugs.llvm.org/show_bug.cgi?id=40923. It appears to me that they are the same issue.Spineless
Your welcome, Ive worked around my one case by making the constructor take T iso any and forward the value. Some static assert of sfinea can be used to restrict T to any, if relevantBiagio
No error with clang-11 and up.Metalline
H
0

If so, how do I make the B copy constructor work as I am intending it to do?

I think the simplest solution would be to replace B(const B& b) : A(b) {} with B(const B& b) = default; (or just removing this line). Then your program will be accepted by Clang 5, demo: https://gcc.godbolt.org/z/vzE3s16hs

The other option is to change standard library implementation from GNU libstdc++ to Clang's own libc++, which is done by -stdlib=libc++ command line option. Then your original code will be accepted as is, demo: https://godbolt.org/z/6ndTdGGE7

Howlend answered 26/1, 2022 at 21:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.