挖两个bug: no member named 'value' in 'std::is_copy_constructible'

@vrqq  September 24, 2021

The first sample code
GodBolt full link && short link https://godbolt.org/z/zcsW65f7P
bugreport: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165

#include <variant>
#include <unordered_map>

class C{
    struct Inner {
        int a = 0;
    };
    struct Outer {
        Inner memx;
    };
    std::unordered_map<int, std::variant<Outer>> table;
};

int main() {}

原因详见bugreport内StackOverflow链接,似乎也是因为dependency cycle。。
https://stackoverflow.com/a/53423881/12529885

The second sample code
Godbolt full link && short link https://godbolt.org/z/5dr4hMb8a
bugreport: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90415

#include <type_traits>
#include <any>
// #include <tuple>

class Adapter {
public:
    Adapter(std::any cfg) {}
};

int main() {
    bool b = std::is_copy_constructible<Adapter>::value;
    // bool c = std::is_copy_constructible<std::tuple<std::any>>::value;
    return 0;
}

The gcc and clang with difference versions show different result, someone passed but someone failed.
I use rhel 8.4 with the gcc-8.4.1 and clang 11.0.0 from official rhel repo.

以第二个的编译器报错举例(节选)

/usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/type_traits:132:31: error: no member named 'value' in 'std::is_copy_constructible<Adapter>'
    : public conditional<_B1::value, _B2, _B1>::type
                         ^^^^^^

/usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/any:170:17: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<Adapter>, std::is_constructible<Adapter, const Adapter &>>' requested here
      enable_if<__and_<is_copy_constructible<_Tp>,

/usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/any:183:7: note: while substituting prior template arguments into non-type template parameter [with _ValueType = const Adapter &, _Tp = Adapter, _Mgr = std::any::_Manager_internal<Adapter>]
      any(_ValueType&& __value)
      ^^^^^^^^^^^^^^^^^^^^^^^^^

/usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/type_traits:873:56: note: while substituting deduced template arguments into function template 'any' [with _ValueType = const Adapter &, _Tp = (no value), _Mgr = (no value), $3 = (no value), $4 = (no value)]
      : public __bool_constant<__is_constructible(_Tp, _Args...)>
                                                       ^

/usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/type_traits:897:14: note: in instantiation of template class 'std::__is_copy_constructible_impl<Adapter, true>' requested here
    : public __is_copy_constructible_impl<_Tp>

../study/test_gnudeduce.cpp:19:19: note: in instantiation of template class 'std::is_copy_constructible<Adapter>' requested here
    bool a = std::is_copy_constructible<Adapter>::value;

节选了一段 进去里看看发现问题如下

  • __is_constructible is compiler intrinsic function : https://clang.llvm.org/docs/LanguageExtensions.html#id18
  • is_copy_constructible的原理是检查T(const T&)是否可以构建
  • 于是正中下怀,触发了Adapter(std::any = const Adapter&)
  • 可巧不巧std::any要求single values of any copy constructible type : https://en.cppreference.com/w/cpp/utility/any
  • 于是在std::any构造函数展开模板时 又检查了is_copy_constructible 回到第一条
  • --- 上面绕圈圈了 ---
  • --- 其实我也不确定是否是绕圈圈引起的问题 ---

修了吗?

修了 但又没完全修,有的用clang + llvm-libcxx可以绕开,有的用clang + stdlibc++可以但gcc + stdlibc++不行。。

怎么办呢?一些解决办法如下

class C {
    Adapter();
    Adapter(std::any, int);
    Adapter(int, std::any);
};

class C {
    template<typename ...Args>
    Adapter(Args&& ...cfg) { init(std::forward<Args>(cfg)...); }
    void init(std::any) {}
};

闲话太多 希望以后言简意赅


添加新评论