如何将智能指针向量转换为包含指向常量的智能指针的常量向量?
How do you cast a vector of smart pointers to a constant vector that hold smart pointers that point to constants?
我有一个叫 Thing
的 class。
我制作了一个 shared_ptr<Thing>>
的向量。
现在我想将它传递给一个函数或类似这样的东西:const vector<shared_ptr<const Thing>>
.
下面的代码可以编译,但为了类型安全,我宁愿避免使用 reinterpret_cast
,因为我不知道这会如何影响智能指针的行为。
#include <memory>
#include <vector>
using namespace std;
class Thing {};
typedef vector<shared_ptr<Thing>> VectorOfThings;
typedef const vector<shared_ptr<const Thing>> VectorOfConstThings;
int main() {
VectorOfThings *things;
auto constThings = reinterpret_cast<VectorOfConstThings *> (things);
}
这与智能指针无关; C++ 标准不允许在 container 和 container 之间进行转换。这个之前有讲过:
Why is a vector of pointers not castable to a const vector of const pointers?
很可能将 conainter 转换为 container 是未定义的行为。
我写了一个宏来处理类型转换。希望这将消除因编写所有样板代码而产生的错误。
TypeHelper.h
#ifndef TYPE_HELPER_H
#define TYPE_HELPER_H
#include <memory>
/**
* Creates a struct that has two typedefs and has several functions for reinterpret casting the regular type as
* the constant type
* @param NAME The name of the generated struct
* @param REGULAR_TYPE The typedef of the non-constant type
* @param CONSTANT_TYPE The typedef of the constant type
* @param ... The template parameters used in REGULAR_TYPE and CONSTANT_TYPE.
* There must be at least one parameter passed in. Even if the typedefs don't actually use them.
* TODO If the typedefs don't need a template parameter, the user should not have to supply a dummy one.
* TODO Implement some kind of checking to make sure that constness is the only difference.
* TODO what happens if the template is specialized for a const of that type?
*/
#define TYPE_HELPER( NAME, REGULAR_TYPE, CONSTANT_TYPE, ... ) \
template< __VA_ARGS__ > \
struct NAME { \
typedef REGULAR_TYPE regular; \
typedef CONSTANT_TYPE constant; \
static inline constant *cast( regular *pointer ) { return reinterpret_cast<constant *> (pointer); } \
static inline constant &cast( regular &reference ) { return *reinterpret_cast<constant *> (&reference); } \
static inline std::unique_ptr<constant> cast( std::unique_ptr<regular> unique_ptr ) { \
return std::move( *( reinterpret_cast<std::unique_ptr<constant> *> (&unique_ptr))); \
} \
static inline std::shared_ptr<constant> cast( std::shared_ptr<regular> shared_ptr ) { \
return std::move( *( reinterpret_cast<std::shared_ptr<constant> *> (&shared_ptr))); \
} \
};
#endif //TYPE_HELPER_H
在此文件中,我使用宏定义了 stl 向量的包装器 class
#ifndef VECTOR_TYPE_H
#define VECTOR_TYPE_H
#include <vector>
#include "TypeHelper.h"
TYPE_HELPER( VectorType,
std::vector<std::shared_ptr<T>>,
const std::vector<std::shared_ptr<const T>>,
typename T );
#endif //VECTOR_TYPE_H
最后,我在这里使用类型
#include "VectorType.h"
//This is a vector of std::shared_ptr<std::string>
VectorType<std::string>::regular strings;
//This is a const vector of std::shared_ptr<const str::string>
//note that I needed to use the cast function to assign the regular one to the constant one
VectorType<std::string>::constant constStrings = VectorType<std::string>::cast(strings);
// You don't have to actually type it twice. Use auto.
auto autoConstStrings = VectorType<std::string>::cast(strings);
我有一个叫 Thing
的 class。
我制作了一个 shared_ptr<Thing>>
的向量。
现在我想将它传递给一个函数或类似这样的东西:const vector<shared_ptr<const Thing>>
.
下面的代码可以编译,但为了类型安全,我宁愿避免使用 reinterpret_cast
,因为我不知道这会如何影响智能指针的行为。
#include <memory>
#include <vector>
using namespace std;
class Thing {};
typedef vector<shared_ptr<Thing>> VectorOfThings;
typedef const vector<shared_ptr<const Thing>> VectorOfConstThings;
int main() {
VectorOfThings *things;
auto constThings = reinterpret_cast<VectorOfConstThings *> (things);
}
这与智能指针无关; C++ 标准不允许在 container
很可能将 conainter
我写了一个宏来处理类型转换。希望这将消除因编写所有样板代码而产生的错误。
TypeHelper.h
#ifndef TYPE_HELPER_H
#define TYPE_HELPER_H
#include <memory>
/**
* Creates a struct that has two typedefs and has several functions for reinterpret casting the regular type as
* the constant type
* @param NAME The name of the generated struct
* @param REGULAR_TYPE The typedef of the non-constant type
* @param CONSTANT_TYPE The typedef of the constant type
* @param ... The template parameters used in REGULAR_TYPE and CONSTANT_TYPE.
* There must be at least one parameter passed in. Even if the typedefs don't actually use them.
* TODO If the typedefs don't need a template parameter, the user should not have to supply a dummy one.
* TODO Implement some kind of checking to make sure that constness is the only difference.
* TODO what happens if the template is specialized for a const of that type?
*/
#define TYPE_HELPER( NAME, REGULAR_TYPE, CONSTANT_TYPE, ... ) \
template< __VA_ARGS__ > \
struct NAME { \
typedef REGULAR_TYPE regular; \
typedef CONSTANT_TYPE constant; \
static inline constant *cast( regular *pointer ) { return reinterpret_cast<constant *> (pointer); } \
static inline constant &cast( regular &reference ) { return *reinterpret_cast<constant *> (&reference); } \
static inline std::unique_ptr<constant> cast( std::unique_ptr<regular> unique_ptr ) { \
return std::move( *( reinterpret_cast<std::unique_ptr<constant> *> (&unique_ptr))); \
} \
static inline std::shared_ptr<constant> cast( std::shared_ptr<regular> shared_ptr ) { \
return std::move( *( reinterpret_cast<std::shared_ptr<constant> *> (&shared_ptr))); \
} \
};
#endif //TYPE_HELPER_H
在此文件中,我使用宏定义了 stl 向量的包装器 class
#ifndef VECTOR_TYPE_H
#define VECTOR_TYPE_H
#include <vector>
#include "TypeHelper.h"
TYPE_HELPER( VectorType,
std::vector<std::shared_ptr<T>>,
const std::vector<std::shared_ptr<const T>>,
typename T );
#endif //VECTOR_TYPE_H
最后,我在这里使用类型
#include "VectorType.h"
//This is a vector of std::shared_ptr<std::string>
VectorType<std::string>::regular strings;
//This is a const vector of std::shared_ptr<const str::string>
//note that I needed to use the cast function to assign the regular one to the constant one
VectorType<std::string>::constant constStrings = VectorType<std::string>::cast(strings);
// You don't have to actually type it twice. Use auto.
auto autoConstStrings = VectorType<std::string>::cast(strings);