如何静态地检查 shared_ptr 类型是否为 <type>?

问题描述 投票:0回答:5

我想创建一个应该存储实例的模板容器类

ABC
派生类。有一个限制,只有
ABC
派生类可以使用这个模板。

容器应该是派生类的静态成员。

这就是我现在所拥有的,尽管这行不通,因为

extendsABC
并不期待
shared_ptr

#include <list>
#include <memory>
#include <type_traits>

class ABC {
  virtual void foo() = 0;
};

template <typename T>
concept extendsABC = std::is_base_of<ABC, T>::value;

template <extendsABC T>
struct extendsABCStore {
  std::list<T> m_data;
};

struct Derived;

struct Derived : public ABC {
  void foo() override{};
  static extendsABCStore<std::shared_ptr<Derived>> instances;
};

构建输出

<source>:22:10: error: constraints not satisfied for class template 'extendsABCStore' [with T = std::shared_ptr<Derrived>]
  static extendsABCStore < std::shared_ptr < Derrived >> instances;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:13:12: note: because 'std::shared_ptr<Derrived>' does not satisfy 'extendsABC'
template < extendsABC T >
           ^
<source>:11:24: note: because 'std::is_base_of<ABC, shared_ptr<Derrived> >::value' evaluated to false
  concept extendsABC = std::is_base_of<ABC, T>::value;
                       ^
1 error generated.
Compiler returned: 1
c++ templates shared-ptr smart-pointers c++-concepts
5个回答
2
投票

你有几个问题。在

Derrived
的定义中,它是一个不完全类型,所以
extendsABC < Derrived >
false
。你还有一个指针,你想在指向的类型上进行约束。

为了解决第一个问题,我们可以使用静态成员函数而不是静态数据成员。

struct Derived : public ABC {
  void foo() override{};
  static auto& instances() {
    static extendsABCStore<Derived> store;
    return store;
  }
};

要确定第二个,将

std::shared_ptr
放在
extendsABCStore

的定义中
template <typename T>
struct extendsABCStore {
  std::list<std::shared_ptr<T>> m_data;
};

godbolt 的完整示例。


1
投票

这里的问题不在于定义概念。这可以做为

template<class T>
struct is_extendsABC : std::false_type {};

template<class T>
struct is_extendsABC<std::shared_ptr<T>> : std::bool_constant<std::is_base_of_v<ABC, T>> {};

template<typename T>
concept extendsABC = is_extendsABC<T>::value;

这里的问题是你使用的概念的类型(

Derrived
)在使用时是不完整的(
instances
成员声明)。

您可以通过延迟类型检查直到

extendsABCStore
专门化来解决此问题:

template <class T>
struct extendsABCStore {
    std::list<T> m_data;

    static_assert(extendsABC<T>, "T needs to be a std::shared_ptr with an element type derived from ABC");
};

Godbolt 演示


0
投票

您需要编写一个采用类型

T
并返回:

的元函数
  • T
    如果
    T
    不是
    shared_ptr
  • shared_ptr
    否则指向的类型。
template<typename T>
struct remove_shared_ptr { using type = T; };
template<typename T>
struct remove_shared_ptr<std::shared_ptr<T>> { using type = T; };

template<typename T>
using remove_shared_ptr_t = typename remove_shared_ptr<T>::type;

// ...

template < typename T >
  concept extendsABC = std::is_base_of<ABC, remove_shared_ptr_t<T> >::value;

0
投票

我能理解错误:

std::shared_ptr<Derrived>
是指向 Derrived 类的智能指针。

您在

is_base_of trait
概念中使用的
extendsABC
也需要类类型。

但是,我在这里看不到实用的解决方案。您尝试实施它的方式似乎是不可能的。尝试创建一个单独的容器类,而不将其绑定到任何特定的派生类。


0
投票

因为概念不直接支持模板模板参数,您可以通过使用辅助类型特征引入额外的间接层来处理,如下所示:

#include <type_traits>
#include <list>
#include <memory>

class ABC {
public:
    virtual void foo() = 0;
};

template <typename T>
concept extendsABC = std::is_base_of<ABC, T>::value;

template <typename T>
struct TypeWrapper {
    using type = T;
};

template <typename T>
using TypeWrapper_t = typename TypeWrapper<T>::type;

template <typename T>
struct extendsABCStore {
   std::list<T> m_data;
};

struct Derrived;

struct Derrived: public ABC {
    void foo() override {};
    static extendsABCStore<TypeWrapper_t<std::shared_ptr<Derrived>>> instances;
};

extendsABCStore<TypeWrapper_t<std::shared_ptr<Derrived>>> Derrived::instances;

int main() {
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.