英文:
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;
};
<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 <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<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
答案1
得分: 2
在Derived
的定义内部,它是一个不完整的类型,所以extendsABC<Derived>
是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;
};
英文:
You have a couple of problems. Within the definition of Derived
, it is an incomplete type, so extendsABC<Derived>
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& instances() {
static extendsABCStore<Derived> store;
return store;
}
};
To fix the second, put std::shared_ptr
in the definition of extendsABCStore
template <typename T>
struct extendsABCStore {
std::list<std::shared_ptr<T>> m_data;
};
答案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
英文:
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");
};
答案3
得分: 0
You need to code a meta-function that takes a type T
, and returns:
T
ifT
is not ashared_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
ifT
is not ashared_ptr
- The type pointed 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;
答案4
得分: 0
我可以理解这些错误:
std::shared_ptr<Derived>
是指向 Derived
类的智能指针。
同时,您在 extendsABC
概念中使用的 is_base_of trait
需要一个类类型。
但是,我在这里看不到一个实际的解决方案。似乎无法按照您尝试实现的方式来做。尝试创建一个不与任何特定派生类绑定的单独的容器类。
英文:
I can understand the errors:
std::shared_ptr<Derived>
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 <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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论