如何在静态情况下检查 shared_ptr 类型是否为

huangapple go评论37阅读模式
英文:

How to check if a shared_ptr type is of <type> statically?

问题

I want to create a template container-class that should store instances of ABC-derived classes. With a constraint that only ABC-derived classes can use this template.

The container should be a static member of the derived class.

This is what I have now, though this won't work since extendsABC is not expecting a 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;
};

Build output:

<source>:22:10: error: constraints not satisfied for class template 'extendsABCStore' [with T = std::shared_ptr<Derived>]
  static extendsABCStore < std::shared_ptr < Derived >> instances;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:13:12: note: because 'std::shared_ptr<Derived>' does not satisfy 'extendsABC'
template < extendsABC T >
           ^
<source>:11:24: note: because 'std::is_base_of<ABC, shared_ptr<Derived> >::value' evaluated to false
  concept extendsABC = std::is_base_of<ABC, T>::value;
                       ^
1 error generated.
Compiler returned: 1
英文:

I want to create a template container-class that should store instances
of ABC-derived classes. With a constraint that only ABC-derived classes can use this template.

The container should be a static member of the derived class.

This is what I have now, though this won't work since extendsABC is not expecting a shared_ptr:

#include &lt;list&gt;
#include &lt;memory&gt;
#include &lt;type_traits&gt;

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

template &lt;typename T&gt;
concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;

template &lt;extendsABC T&gt;
struct extendsABCStore {
  std::list&lt;T&gt; m_data;
};

struct Derived;

struct Derived : public ABC {
  void foo() override{};
  static extendsABCStore&lt;std::shared_ptr&lt;Derived&gt;&gt; instances;
};

Build output:

&lt;source&gt;:22:10: error: constraints not satisfied for class template &#39;extendsABCStore&#39; [with T = std::shared_ptr&lt;Derived&gt;]
  static extendsABCStore &lt; std::shared_ptr &lt; Derived &gt;&gt; instances;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;source&gt;:13:12: note: because &#39;std::shared_ptr&lt;Derived&gt;&#39; does not satisfy &#39;extendsABC&#39;
template &lt; extendsABC T &gt;
           ^
&lt;source&gt;:11:24: note: because &#39;std::is_base_of&lt;ABC, shared_ptr&lt;Derived&gt; &gt;::value&#39; evaluated to false
  concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;
                       ^
1 error generated.
Compiler returned: 1

答案1

得分: 2

Derived的定义内部,它是一个不完整的类型,所以extendsABC&lt;Derived&gt;false。你还有一个指针,你想在指向的类型上施加限制。

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

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

为了修复第二个问题,在extendsABCStore的定义中加入std::shared_ptr

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

完整示例请参见godbolt。

英文:

You have a couple of problems. Within the definition of Derived, it is an incomplete type, so extendsABC&lt;Derived&gt; is false. You also have a pointer where you want to constrain on the pointed-to type.

To fix the first, we can use a static member function rather than a static data member.

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

To fix the second, put std::shared_ptr in the definition of extendsABCStore

template &lt;typename T&gt;
struct extendsABCStore {
  std::list&lt;std::shared_ptr&lt;T&gt;&gt; m_data;
};

Full example at godbolt.

答案2

得分: 1

The problem here is not so much defining the concept. This can be done as

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;

The problem here is that you're using a concept with a type (Derived) that is incomplete at the time of use (instances member declaration).

You could work around this by delaying the check of the type until extendsABCStore is specialized:

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 demo](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:6,endLineNumber:38,positionColumn:6,positionLineNumber:38,selectionStartColumn:6,selectionStartLineNumber:38,startColumn:6,startLineNumber:38),source:'#include <type_traits>\n#include \n#include \n\nclass ABC {\n virtual void foo() = 0;\n};\n\n\n\n\ntemplate\nstruct is_extendsABC : std::false_type {};\n\n\n\n\n\n\ntemplate\nstruct is_extendsABC<std::shared_ptr> : std::bool_constant<std::is_base_of_v<ABC, T>> {};\n\n\ntemplate\nconcept extendsABC = is_extendsABC::value;\n\n\ntemplate \nstruct extendsABCStore {\n std::list m_data;\n\n static_assert(extendsABC, "T needs to be a std::shared_ptr with an element type derived from ABC");\n};\n'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),(g:!((h:conformance,i:(compilers:!((compilerId:gsnapshot,options:'-std=c%2B%2B20'),(compilerId:clang_trunk,options:'-std=c%2B%2B20'),(compilerId:vcpp_v19_latest_x64,options:'/std:c%2B%2B20')),editorid:1,langId:c%2B%2B,libs:!()),l:'5',n:'0',o:'Conformance+Viewer+(Editor+%231)+3/15',t:'0')),header:(),k:50,l:'4',n:'0',o:'',s:0,t:'0'))),l:'2',n:'0',o:'',t:'0')),version:4

英文:

The problem here is not so much defining the concept. This can be done as

template&lt;class T&gt;
struct is_extendsABC : std::false_type {};

template&lt;class T&gt;
struct is_extendsABC&lt;std::shared_ptr&lt;T&gt;&gt; : std::bool_constant&lt;std::is_base_of_v&lt;ABC, T&gt;&gt; {};

template&lt;typename T&gt;
concept extendsABC = is_extendsABC&lt;T&gt;::value;

The problem here is that you're using a concept with a type (Derived) that is incomplete at the time of use (instances member declaration).

You could work around this by delaying the check of the type until extendsABCStore is specialized:

template &lt;class T&gt;
struct extendsABCStore {
    std::list&lt;T&gt; m_data;

    static_assert(extendsABC&lt;T&gt;, &quot;T needs to be a std::shared_ptr with an element type derived from ABC&quot;);
};

Godbolt demo

答案3

得分: 0

You need to code a meta-function that takes a type T, and returns:

  • T if T is not a shared_ptr
  • The type pointed to by the shared_ptr otherwise.
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;
英文:

You need to code a meta-function that takes a type T, and returns:

  • T if T is not a shared_ptr
  • The type pointed by the shared_ptr otherwise.
template&lt;typename T&gt;
struct remove_shared_ptr { using type = T; };
template&lt;typename T&gt;
struct remove_shared_ptr&lt;std::shared_ptr&lt;T&gt;&gt; { using type = T; };

template&lt;typename T&gt;
using remove_shared_ptr_t = typename remove_shared_ptr&lt;T&gt;::type;

// ...

template &lt; typename T &gt;
  concept extendsABC = std::is_base_of&lt;ABC, remove_shared_ptr_t&lt;T&gt; &gt;::value;

答案4

得分: 0

我可以理解这些错误:

std::shared_ptr&lt;Derived&gt; 是指向 Derived 类的智能指针。

同时,您在 extendsABC 概念中使用的 is_base_of trait 需要一个类类型。

但是,我在这里看不到一个实际的解决方案。似乎无法按照您尝试实现的方式来做。尝试创建一个不与任何特定派生类绑定的单独的容器类。

英文:

I can understand the errors:

std::shared_ptr&lt;Derived&gt; is a smart pointer to the Derived class.

also is_base_of trait which you use in the extendsABC concept expects a class type.

However, I don't see a practical solution here. Seems impossible the way you try to implement it. Try creating a separate container class without tying it to any specific dirived class.

答案5

得分: 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 Derived;

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

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

int main() {
    return 0;
}
英文:

Because concepts do not support template template parameters directly you can handle by introduce an extra layer of indirection using a helper type trait like this:

#include &lt;type_traits&gt;
#include &lt;list&gt;
#include &lt;memory&gt;

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

template &lt;typename T&gt;
concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;

template &lt;typename T&gt;
struct TypeWrapper {
    using type = T;
};

template &lt;typename T&gt;
using TypeWrapper_t = typename TypeWrapper&lt;T&gt;::type;

template &lt;typename T&gt;
struct extendsABCStore {
   std::list&lt;T&gt; m_data;
};

struct Derived;

struct Derived: public ABC {
    void foo() override {};
    static extendsABCStore&lt;TypeWrapper_t&lt;std::shared_ptr&lt;Derived&gt;&gt;&gt; instances;
};

extendsABCStore&lt;TypeWrapper_t&lt;std::shared_ptr&lt;Derived&gt;&gt;&gt; Derived::instances;

int main() {
    return 0;
}

huangapple
  • 本文由 发表于 2023年5月10日 19:15:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76217741.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定