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

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

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:

  1. #include <list>
  2. #include <memory>
  3. #include <type_traits>
  4. class ABC {
  5. virtual void foo() = 0;
  6. };
  7. template <typename T>
  8. concept extendsABC = std::is_base_of<ABC, T>::value;
  9. template <extendsABC T>
  10. struct extendsABCStore {
  11. std::list<T> m_data;
  12. };
  13. struct Derived;
  14. struct Derived : public ABC {
  15. void foo() override{};
  16. static extendsABCStore<std::shared_ptr<Derived>> instances;
  17. };

Build output:

  1. <source>:22:10: error: constraints not satisfied for class template 'extendsABCStore' [with T = std::shared_ptr<Derived>]
  2. static extendsABCStore < std::shared_ptr < Derived >> instances;
  3. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. <source>:13:12: note: because 'std::shared_ptr<Derived>' does not satisfy 'extendsABC'
  5. template < extendsABC T >
  6. ^
  7. <source>:11:24: note: because 'std::is_base_of<ABC, shared_ptr<Derived> >::value' evaluated to false
  8. concept extendsABC = std::is_base_of<ABC, T>::value;
  9. ^
  10. 1 error generated.
  11. 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:

  1. #include &lt;list&gt;
  2. #include &lt;memory&gt;
  3. #include &lt;type_traits&gt;
  4. class ABC {
  5. virtual void foo() = 0;
  6. };
  7. template &lt;typename T&gt;
  8. concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;
  9. template &lt;extendsABC T&gt;
  10. struct extendsABCStore {
  11. std::list&lt;T&gt; m_data;
  12. };
  13. struct Derived;
  14. struct Derived : public ABC {
  15. void foo() override{};
  16. static extendsABCStore&lt;std::shared_ptr&lt;Derived&gt;&gt; instances;
  17. };

Build output:

  1. &lt;source&gt;:22:10: error: constraints not satisfied for class template &#39;extendsABCStore&#39; [with T = std::shared_ptr&lt;Derived&gt;]
  2. static extendsABCStore &lt; std::shared_ptr &lt; Derived &gt;&gt; instances;
  3. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. &lt;source&gt;:13:12: note: because &#39;std::shared_ptr&lt;Derived&gt;&#39; does not satisfy &#39;extendsABC&#39;
  5. template &lt; extendsABC T &gt;
  6. ^
  7. &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
  8. concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;
  9. ^
  10. 1 error generated.
  11. Compiler returned: 1

答案1

得分: 2

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

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

  1. struct Derived : public ABC {
  2. void foo() override{};
  3. static auto& instances() {
  4. static extendsABCStore<Derived> store;
  5. return store;
  6. }
  7. };

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

  1. template <typename T>
  2. struct extendsABCStore {
  3. std::list<std::shared_ptr<T>> m_data;
  4. };

完整示例请参见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.

  1. struct Derived : public ABC {
  2. void foo() override{};
  3. static auto&amp; instances() {
  4. static extendsABCStore&lt;Derived&gt; store;
  5. return store;
  6. }
  7. };

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

  1. template &lt;typename T&gt;
  2. struct extendsABCStore {
  3. std::list&lt;std::shared_ptr&lt;T&gt;&gt; m_data;
  4. };

Full example at godbolt.

答案2

得分: 1

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

  1. template<class T>
  2. struct is_extendsABC : std::false_type {};
  3. template<class T>
  4. struct is_extendsABC<std::shared_ptr<T>> : std::bool_constant<std::is_base_of_v<ABC, T>> {};
  5. template<typename T>
  6. 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:

  1. template <class T>
  2. struct extendsABCStore {
  3. std::list<T> m_data;
  4. static_assert(extendsABC<T>, "T needs to be a std::shared_ptr with an element type derived from ABC");
  5. };

[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

  1. template&lt;class T&gt;
  2. struct is_extendsABC : std::false_type {};
  3. template&lt;class T&gt;
  4. 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; {};
  5. template&lt;typename T&gt;
  6. 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:

  1. template &lt;class T&gt;
  2. struct extendsABCStore {
  3. std::list&lt;T&gt; m_data;
  4. static_assert(extendsABC&lt;T&gt;, &quot;T needs to be a std::shared_ptr with an element type derived from ABC&quot;);
  5. };

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.
  1. template<typename T>
  2. struct remove_shared_ptr { using type = T; };
  3. template<typename T>
  4. struct remove_shared_ptr<std::shared_ptr<T>> { using type = T; };
  5. template<typename T>
  6. using remove_shared_ptr_t = typename remove_shared_ptr<T>::type;
  7. // ...
  8. template <typename T>
  9. 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.
  1. template&lt;typename T&gt;
  2. struct remove_shared_ptr { using type = T; };
  3. template&lt;typename T&gt;
  4. struct remove_shared_ptr&lt;std::shared_ptr&lt;T&gt;&gt; { using type = T; };
  5. template&lt;typename T&gt;
  6. using remove_shared_ptr_t = typename remove_shared_ptr&lt;T&gt;::type;
  7. // ...
  8. template &lt; typename T &gt;
  9. 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

因为概念不直接支持模板模板参数,您可以通过引入额外的间接层次来处理,使用一个类似这样的帮助类型特性:

  1. #include <type_traits>
  2. #include <list>
  3. #include <memory>
  4. class ABC {
  5. public:
  6. virtual void foo() = 0;
  7. };
  8. template <typename T>
  9. concept extendsABC = std::is_base_of<ABC, T>::value;
  10. template <typename T>
  11. struct TypeWrapper {
  12. using type = T;
  13. };
  14. template <typename T>
  15. using TypeWrapper_t = typename TypeWrapper<T>::type;
  16. template <typename T>
  17. struct extendsABCStore {
  18. std::list<T> m_data;
  19. };
  20. struct Derived;
  21. struct Derived: public ABC {
  22. void foo() override {};
  23. static extendsABCStore<TypeWrapper_t<std::shared_ptr<Derived>>> instances;
  24. };
  25. extendsABCStore<TypeWrapper_t<std::shared_ptr<Derived>>> Derived::instances;
  26. int main() {
  27. return 0;
  28. }
英文:

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:

  1. #include &lt;type_traits&gt;
  2. #include &lt;list&gt;
  3. #include &lt;memory&gt;
  4. class ABC {
  5. public:
  6. virtual void foo() = 0;
  7. };
  8. template &lt;typename T&gt;
  9. concept extendsABC = std::is_base_of&lt;ABC, T&gt;::value;
  10. template &lt;typename T&gt;
  11. struct TypeWrapper {
  12. using type = T;
  13. };
  14. template &lt;typename T&gt;
  15. using TypeWrapper_t = typename TypeWrapper&lt;T&gt;::type;
  16. template &lt;typename T&gt;
  17. struct extendsABCStore {
  18. std::list&lt;T&gt; m_data;
  19. };
  20. struct Derived;
  21. struct Derived: public ABC {
  22. void foo() override {};
  23. static extendsABCStore&lt;TypeWrapper_t&lt;std::shared_ptr&lt;Derived&gt;&gt;&gt; instances;
  24. };
  25. extendsABCStore&lt;TypeWrapper_t&lt;std::shared_ptr&lt;Derived&gt;&gt;&gt; Derived::instances;
  26. int main() {
  27. return 0;
  28. }

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:

确定