6

我刚刚遇到了好奇的 std::experimental::propagate_const 错误。下面的代码片段演示了这个问题

#include <memory>
#include <experimental/propagate_const>
#include <map>

class FWD;

//compiles
class A
{
    std::unique_ptr<FWD> m;
};

//compiles
class B
{
    std::experimental::propagate_const<std::unique_ptr<FWD>> m;
};

//compiles
class C
{
    std::unique_ptr<std::map<int, FWD>> m;
};

//does not compile!
class D
{
    std::experimental::propagate_const<std::unique_ptr<std::map<int, FWD>>> m;
};

因此,您不能只用传播 unique_ptr 替换 unique_ptr,因为有时您的前向声明会破坏它。

如果有人能向我解释为什么在当前的传播实现中编译失败,我将不胜感激。它与

typedef remove_reference_t<decltype(*std::declval<_Tp&>())> element_type;

因为解决方法是:

template <typename T, typename = void>
struct get_element_type
{
  using type = std::remove_reference_t<decltype(*std::declval<T&>())>;
};

template <typename T>
struct get_element_type<T, typename std::enable_if<!std::is_void<typename T::element_type>::value>::type>
{
  using type = typename T::element_type;
};

// Namespaces and class declaration...

using element_type = typename get_element_type<T>::type;

测试编译器:clang、gcc。

PS我想知道编译器开发人员是否知道。

4

2 回答 2

5
  1. 通常禁止实例化具有不完整类型的标准库模板。

  2. std::map也不例外。

  3. 查询decltype(*std::declval<_Tp&>())需要_Tp = std::unique_ptr<std::map<int, FWD>>实例化所有相关的类_Tp来寻找潜在的朋友operator*声明。

  4. 在这些相关的类中是std::map<int, FWD>.

  5. 实例化std::map<int, FWD>调用未定义的行为。

于 2019-02-20T14:37:27.380 回答
0

我已经向propagate_const 提交了一个补丁,该补丁替换了现有的解决方案,并像上述解决方案一样解决了这个问题,但不依赖于SFINAE:

template<class U>
struct detect_element_type {
    using type = typename U::element_type;
};

template<class U>
struct detect_element_type<U*> {
    using type = U;
};

using element_type = typename detect_element_type<T>::type;
于 2019-10-16T15:18:34.090 回答