Try to implement a tiny-any:
#include <iostream>
#include <type_traits>
#include <memory>
class TinyAny
{
public:
template <typename Tp>
TinyAny(Tp&& val) : data(std::make_shared<unsigned char[]>(sizeof(val))) {
new(data.get()) Tp(std::forward<Tp>(val));
}
template <typename Tp>
TinyAny &operator =(Tp&& val)
{
data = std::make_shared<unsigned char[]>(sizeof(val));
new(data.get()) Tp(std::forward<Tp>(val));
return *this;
}
template <typename Tp>
Tp get()
{
return *reinterpret_cast<Tp *>(data.get());
}
private:
std::shared_ptr<unsigned char[]> data;
};
int main() {
// var = "abc";
// std::cout << var.get<const char *>() << std::endl;
}
if uncomment var = "abc" will get the fellowing error:
<source>: In instantiation of 'TinyAny& TinyAny::operator=(Tp&&) [with Tp = const char (&)[4]]':
<source>:40:11: required from here
<source>:17:9: error: new cannot be applied to a reference type
17 | new(data.get()) Tp(std::forward<Tp>(val));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:17:44: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
17 | new(data.get()) Tp(std::forward<Tp>(val));
| ~~~~~~~~~~~~~~~~^~~~~
| |
| const char*
The type of val is const char*, but I cannot understand which one is char? Or, how can I fix this error?
Source Code: https://gcc.godbolt.org/z/zW7fPc6G3
My finally implement:
#include <type_traits>
#include <utility>
class TinyAny
{
template<typename Tp>
class AnyData {
public:
static void create(void **data, Tp && val)
{
*data = new Tp(std::forward<Tp>(val));
}
static void deleter(void *data)
{
auto ptr = static_cast<Tp *>(data);
delete ptr;
}
};
public:
template <typename Tp__, typename Tp = std::decay_t<Tp__>>
TinyAny(Tp__&& val) : deleter(AnyData<Tp>::deleter) {
AnyData<Tp>::create(&data, std::forward<Tp>(val));
}
~TinyAny() {
deleter(data);
data = nullptr;
}
template <typename Tp>
TinyAny &operator = (Tp&& val)
{
TinyAny temp{std::forward<Tp>(val)};
swap(std::move(temp));
return *this;
}
template <typename Tp>
Tp get()
{
return *static_cast<Tp*>(data);
}
private:
TinyAny &swap(TinyAny && another) noexcept
{
std::swap(data, another.data);
std::swap(deleter, another.deleter);
return *this;
}
private:
void *data;
void (* deleter)(void *data);
};
Related
Here is my code which compiles fine for clang but failed with gcc
#include <iostream>
#include <string>
#include <regex>
#include <variant>
struct Id {
void SetValue(const std::string& item)
{
value = item;
}
std::string value;
};
struct Number {
void SetValue(const std::string& item)
{
value = std::stoi(item);
}
int value;
};
using TokenBase
= std::variant<Number, Id>;
struct Token : TokenBase {
using TokenBase::TokenBase;
template <typename T>
[[nodiscard]] bool Is() const {
return std::holds_alternative<T>(*this);
}
template <typename T>
[[nodiscard]] const T& As() const {
return std::get<T>(*this);
}
template <typename T>
[[nodiscard]] const T* TryAs() const {
return std::get_if<T>(this);
}
};
struct LexerTokenExtractor {
const std::string& item_;
void operator()(Number& item) const {
item.SetValue(item_);
}
void operator()(Id& item) const {
item.SetValue(item_);
}
};
int main()
{
const std::string string_token("x");
Token id_token = Id();
std::visit(LexerTokenExtractor{string_token}, id_token);
std::cout << "ok" << std::endl;
}
Here is the log :
required from here
/usr/include/c++/7/variant:97:29: error: incomplete type ‘std::variant_size<Token>’ used in nested name specifier
inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
/usr/include/c++/7/variant: In instantiation of ‘constexpr const auto std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>::_S_vtable’:
/usr/include/c++/7/variant:711:29: required from ‘struct std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>’
/usr/include/c++/7/variant:1255:23: required from ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = LexerTokenExtractor; _Variants = {Token&}]’
1673947047/source.cpp:65:57: required from here
/usr/include/c++/7/variant:711:49: error: ‘_S_apply’ was not declared in this scope
static constexpr auto _S_vtable = _S_apply();
Please give me any ideas of what could be wrong here
As mentioned in the comments, this is a known bug in the current versions of GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90943
A simple workaround would be to force std::visit() to operate directly on the variant instead of the subclass by using a static_cast.
std::visit(LexerTokenExtractor{string_token}, static_cast<TokenBase&>(id_token));
See on godbolt: https://gcc.godbolt.org/z/vMGfahq3z
I'm trying to find a [better] way to run/check a potentially unsafe expression or perform multiple null checks in a more elegant way.
Here is an example of codes I would like to improve:
if (myObjectPointer &&
myObjectPointer->getSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) {
// Use safely target
... *(myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) ...
}
I tried to find a more elegant way to achieve this (instead of the above verbose null checks). Here is my first thoughts:
template<typename T>
bool isSafe(T && function) {
try {
function();
// Just running the func above, but we could e.g. think about returning the actual value instead of true/fase - not that important.
return true;
}
catch (...) {
return false;
}
}
...
// And use the above as follow :
if(isSafe([&](){ myObjectPointer->getSubObject()->getSubSubObject()->getTarget(); })) {
// Use safely target
}
...
The problem with the above is that we can't catch signals (Segmentation fault, ...). And I obviously don't want to handle all signals in the program, but only in this very specific check/eval function.
I'm I tackling the problem the wrong way ? Any other recommendations ? or the verbose if is inevitable ?
Many thanks in advance.
I was thinking about this, and like Jarod42 said, there must be some variadic template stuff. I'm not the best at this, but came up with this:
#include <memory>
#include <functional>
#include <iostream>
template <typename T, typename MemFn, typename... Params>
void safeExecute(T* ptr, MemFn memFn, Params&&... params) {
if (ptr != nullptr)
safeExecute(std::invoke(memFn, ptr), std::forward<Params>(params)...);
}
template <typename T, typename MemFn>
void safeExecute(T* ptr, MemFn memFn) {
if (ptr != nullptr) std::invoke(memFn, ptr);
}
struct Target {
void Bar() { std::cout << "tada!\n"; };
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() : ptr(std::make_unique<T>()) {}
T* Get() { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
safeExecute(myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get,
&Target::Bar);
}
edit:
I've been playing with the idea of having a more general return type, so I experimented with the option not to call the member function, but to return an std::optional pointer to the object. This lead me to the following code:
#include <memory>
#include <functional>
#include <iostream>
#include <optional>
template <typename T, typename MemFn, typename... Params>
auto safeGetObject(T* ptr, MemFn memFn, Params&&... params)
-> decltype(safeGetObject(std::invoke(memFn, std::declval<T>()), std::forward<Params>(params)...))
{
if (ptr != nullptr) return safeGetObject(std::invoke(memFn, ptr), std::forward<Params>(params)...);
return {};
}
template <typename T, typename MemFn>
auto safeGetObject(T* ptr, MemFn memFn) -> std::optional<decltype(std::invoke(memFn, std::declval<T>()))> {
if (ptr != nullptr) return std::invoke(memFn, ptr);
return {};
}
struct Target {
int Bar(int a, int b) const noexcept {
return a+b;
};
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() noexcept : ptr(std::make_unique<T>()) {}
T* Get() const noexcept { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
auto optionalTarget = safeGetObject(
myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get);
auto result = optionalTarget ? optionalTarget.value()->Bar(3, 4) : -1;
std::cout << " result " << result << '\n';
}
Putting possible design issues aside, you could use an extended version of std::optional. Since not all intefaces are under your control, you would have to wrap the functions were necessary into a free-function. Let's assume you can change the class MyClass of myObjectPointer, but not the classes of the sub-objects.
class MyClass {
public:
optional<std::reference_wrapper<SubObjectClass>> getSubObject();
};
optional<std::reference_wrapper<SubSubObjectClass>> getSubSubObject(SubObjectClass& s) {
SubSubObjectClass* ptr = s.getSubSubObject();
if (ptr) {
return std::ref(s.getSubSubObject());
} else {
return {};
}
}
optional<std::reference_wrapper<Target>> getTarget(SubSubObjectCLass& s) {
...
}
You can now write something like
optional<MyClass*> myObjectPointer = ...;
myObjectPointer.and_then(MyClass::getSubObject)
.and_then(getSubSubObject)
.and_then(getTarget)
.map( doSomethingWithTarget ):
OK, I might delete my previous answer, because I've been rethinking this, now considering using std::optional and chaining.
Your original
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()
is not really reproducible, since operator->() cannot be static. But we can use another operator, like operator>>(). Thus:
#include <memory>
#include <iostream>
#include <optional>
#include <functional>
struct Target {
int Bar(int a, int b) const noexcept { return a+b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
Object(T* ptr) noexcept : ptr(ptr) {}
T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template <typename T>
auto makeOptional(T* ptr) -> std::optional< std::reference_wrapper<T>> {
if (ptr) return std::ref(*ptr);
return {};
}
template <typename T, typename MemFn>
auto operator>> (std::optional<std::reference_wrapper<T>> optObj, MemFn memFn)
-> std::optional< std::reference_wrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>> {
if (optObj) return makeOptional(std::invoke(memFn, *optObj));
return {};
}
int main() {
{
//complete
auto TargetPtr = std::make_unique<Target>();
auto subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
{
// incomplete
auto subObjectPtr = std::make_unique<SubObject>(nullptr);
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
}
will work...
Let me know if this is what you're looking for.
edit:
I've also tried putting it in a wrapper class
#include <memory>
#include <iostream>
#include <functional>
#include <optional>
struct Target {
constexpr int Bar(int a, int b) const noexcept { return a + b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
constexpr Object(T* const ptr) noexcept : ptr(ptr) {}
constexpr T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template<typename T>
class ObjectWrapper {
private:
std::optional<std::reference_wrapper<T>> optRefObj{};
public:
constexpr ObjectWrapper(T* ptr) noexcept
: optRefObj(ptr ? std::make_optional(std::ref(*ptr)) : std::nullopt)
{}
template<typename MemFn>
constexpr auto operator>>(MemFn memFn) const noexcept {
return ObjectWrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>
(optRefObj ? std::invoke(memFn, *optRefObj) : nullptr);
}
constexpr operator bool() const noexcept { return optRefObj.has_value(); }
constexpr T* Get() noexcept { return optRefObj ? &optRefObj->get() : nullptr; }
};
int main() {
{
//complete
auto const TargetPtr = std::make_unique<Target>();
auto const subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto const subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
{
// incomplete
auto const subObjectPtr = std::make_unique<SubObject>(nullptr);
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
}
I want to make function get_type_name. For types that belong to certain set example are numbers, geometry etc I want to make one get_type_name function which uses enable_if with type trait. And for each type that do not belong to particular set I want to specialize its own get_type_name function. This is my code and I get the following compiler error and can't figure out why:
error C2668: 'get_type_name': ambiguous call to overloaded function
could be 'std::string get_type_name(myenable_if::type
*)' or 'std::string get_type_name(void *)'
template<bool B, typename T = void>
struct myenable_if {};
template<typename T>
struct myenable_if<true, T> { typedef void type; };
template<class T>
struct is_number
{
static const bool value = false;
};
template<>
struct is_number<int>
{
static const bool value = true;
};
template<class T>
std::string get_type_name(void* v=0);
//get_type_name for specific type
template<>
std::string get_type_name<std::string>(void*)
{
return std::string("string");
}
//get_type_name for set of types
template<class T>
std::string get_type_name(typename myenable_if<is_number<T>::value>::type* t=0)
{
return std::string("number");
}
int main()
{
std::string n = get_type_name<int>();
}
Here is a working version.
#include <iostream>
#include <string>
#include <vector>
#include <iostream>
template<bool B, typename T = void>
struct myenable_if {};
template<typename T>
struct myenable_if<true, T> { typedef T type; };
template<class T>
struct is_number
{
static const bool value = false;
};
template<>
struct is_number<int>
{
static const bool value = true;
};
template<class T>
std::string get_type_name_helper(void* t, char)
{
return "normal";
}
template<class T>
typename myenable_if<is_number<T>::value, std::string>::type get_type_name_helper(void* t, int)
{
return "number";
}
//get_type_name for specific type
template<>
std::string get_type_name_helper<std::string>(void* t, char)
{
return std::string("string");
}
template <class T>
std::string get_type_name(void* t = 0)
{
return get_type_name_helper<T>(t, 0);
}
int main() {
std::string n = get_type_name<int>();
std::cout << n << '\n';
n = get_type_name<std::string>();
std::cout << n << '\n';
n = get_type_name<float>();
std::cout << n << '\n';
return 0;
}
See Live Demo
I am new to SFINAE. I have a template that I would like to be able to accept classes that the size could be determined simply calling sizeof(x) or in case the value is dynamic it will require x.size().
I am trying to wrap my head around how as smooth as possible this could looks like and I think interface: size_t size(const Item& item) seems to be good enough.
The following is an example that works:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static const bool kFixedSize = true;
static size_t size() {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static const bool kFixedSize = false;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
template <typename = typename std::enable_if<T::kFixedSize> >
size_t size(typename T::Item&) {
return T::size();
}
template <typename = typename std::enable_if<!T::kFixedSize> >
size_t size(const typename T::Item& item) {
return T::size(item);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size("string") << std::endl;
return 0;
}
It has an issues though one is: size_t size(typename T::Item&) and the other is size_t size(const typename T::Item& item) else the compiler compliance that I am overloading the template. The second is it seems like too match very tricky code to achieve the goal - is there better ways to do this?
I believe you want something like this
//class hierarchy to set the priority for type matching
struct second_priority
{
};
struct first_priority : public second_priority
{};
template<typename T>
auto size_impl(T const & data, second_priority t) -> int
{
return sizeof(data);
}
template<typename T>
auto size_impl(T const & data , first_priority t) -> decltype(data.size(),int())
{
return data.size();
}
template<typename T>
int size(T const & data )
{
return size_impl(data,first_priority{});
}
I think #Gautam Jha presented a nice solution using SFINAE. You can shorten it a bit by using ellipsis for the 'else' case, so you don't need to use this auxiliary class and it's inheritance:
template<typename T>
auto size_impl(T const & item, int) -> decltype(item.size())
{
return item.size();
}
template<typename T>
auto size_impl(T const & item, ...) -> size_t
{
return sizeof(T);
}
template<typename T>
auto size(T const & item) -> size_t
{
return size_impl(item, 0);
}
It's cool that you're playing around with SFINAE, but usually there are simpler (i.e. to read and to understand) ways to achieve the same, see the solution of POW (which has unfortunately been deleted).
Since all you want to do is call different functions to get the size in Dynamic or Fixed, you can just implement these classes differently and use them in Serialize:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static size_t size(const T&) {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
size_t size(typename T::Item const& x) {
return T::size(x);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
return 0;
}
However, I would consider using a type-trait or a free function to do the same. This would be more extensible, because you have to just provide a new trait or an overload for new types, e.g. some container which has only a length method.
#include <iostream>
#include <cstdio>
#include <type_traits>
size_t size(int) {return sizeof(int);}
size_t size(std::string const& s) {return s.size();}
template<typename T>
struct size_trait
{
};
template<>
struct size_trait<int>
{
static size_t size(int) {return sizeof(int);}
};
template<>
struct size_trait<std::string>
{
static size_t size(std::string const& x) {return x.size();}
};
template <typename T>
class Serialize {
public:
size_t size(T const& x) {
return ::size(x);
}
size_t size_(T const& x) {
return size_trait<T>::size(x);
}
};
int main() {
Serialize< int > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
std::cout << fixed.size_(a) << std::endl;
Serialize< std::string > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
std::cout << dynamic.size_( std::string{"string"} ) << std::endl;
return 0;
}
#include "stdafx.h"
#include <exception>
template<class T>
class NoCheck;
template<class T>
class EnforceNotNull
{
public:
//EnforceNotNull(const NoCheck<T>&){}//<<-----If this is uncommented it works
static void Check(T* p)
{
class NullPtrException : public std::exception
{
};
if (!p)
{
throw NullPtrException();
}
}
};
template<class T>
class NoCheck
{
public:
NoCheck(){}
NoCheck(const NoCheck&){}
NoCheck(const EnforceNotNull<T>&){}
operator EnforceNotNull<T>() {return EnforceNotNull<T>();}//<<-----This seams to not do its job
static void Check(T* p)
{/*Empty body*/}
};
template<class T, template<class> class CheckingPolicy>
class SmartPtr : public CheckingPolicy<T>
{
public:
SmartPtr(T* p)
{
Check(p);
}
template<class T1, template <class> class CheckingPolicy1>
SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_),
CheckingPolicy<T>(pattern)
{
}
T* pointee_;
private:
};
int _tmain(int argc, _TCHAR* argv[])
{
SmartPtr<int,NoCheck> p1(nullptr);
SmartPtr<int,EnforceNotNull> p = p1;//I'm trying here to convert NoCheck to
// EnforceNotNull but it works for me only if I use ctor, if I use conversion optor
//(from
// NoCheck to EnforceNotNull) it doesn't work why?
return 0;
}
I don't see why the SmartPtr has to be inherited from the checking policy at all. Nor do I see why the policy has to be a template itself.
Why not simply:
#include <cstdlib>
#include <exception>
class EnforceNotNull
{
public:
template <class T>
static void Check(T* p)
{
class NullPtrException : public std::exception
{
};
if (!p)
{
throw NullPtrException();
}
}
};
class NoCheck
{
public:
template<class T>
static void Check(T* p)
{/*Empty body*/}
};
template<class T, class CheckingPolicy>
class SmartPtr
{
public:
SmartPtr(T* p)
{
CheckingPolicy::Check(p);
}
template<class T1, class CheckingPolicy1>
SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_)
{
CheckingPolicy::Check(pointee_); //pattern's pointee_ may not pass our check
}
T* pointee_;
private:
};
int main()
{
SmartPtr<int,NoCheck> p1(NULL);
SmartPtr<int,EnforceNotNull> p = p1;
return 0;
}
Your operator EnforceNotNull<T>() function is not const, so the compiler isn't including it in the set of possible conversion functions. Uncomment EnforceNotNull copy ctor or put a const on the above function and your code should work.
Your code looks a little bit overcomplicated. For example, you don't have to inherit a policy unless it cares some state, which is not your case. Plus, having classes requires putting access specifiers, so you might be better off with structs.
Anyways, smart pointers cannot be copied, that is the main trick. You can only transfer ownership (movable concept). So your copy constructor is a bit incorrect. You may still have it if that is clearly your intent, but make sure you have some reference counter whatsoever.
Here is your code, simplified and working:
#include <cstdio>
#include <cstddef>
#include <exception>
class NullPtrException : public std::exception
{
};
template <typename T>
struct EnforceNotNull
{
static void Check(T *p)
{
if (p == NULL)
{
throw NullPtrException();
}
}
};
template <typename T>
struct NoCheck
{
static void Check(T *)
{
}
};
template <typename T, template <typename> class CheckingPolicy>
class SmartPtr
{
T* pointee_;
public:
SmartPtr (T* p) :
pointee_ (p)
{
CheckingPolicy<T>::Check (pointee_);
}
template <typename T1, template <typename> class CheckingPolicy1>
SmartPtr (SmartPtr<T1, CheckingPolicy1> & pattern) :
pointee_ (pattern.get ())
{
CheckingPolicy<T>::Check (pointee_);
pattern.release ();
}
~SmartPtr ()
{
delete pointee_;
pointee_ = NULL;
}
T *get ()
{
return pointee_;
}
T *release ()
{
T *result = pointee_;
pointee_ = NULL;
return result;
}
};
int main()
{
try
{
printf ("Creating NULL pointer...\n");
SmartPtr<int, NoCheck> p1 (NULL);
printf ("Changing policy... \n");
SmartPtr<int, EnforceNotNull> p = p1;
printf ("This doesn't work :-(\n");
}
catch (const NullPtrException &)
{
printf ("GOTCHA!!!\n");
}
}
Here is how you enforce conversions using MPL:
#include <cstdio>
#include <cstddef>
#include <exception>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/or.hpp>
class NullPtrException : public std::exception {};
struct EnforceNotNull
{
template <typename T>
static void Check(T *p)
{
if (p == NULL)
throw NullPtrException();
}
};
struct NoCheck
{
template <typename T>
static void Check(T *) {}
};
template <typename T, typename CheckingPolicy>
class SmartPtr
{
T* p_;
public:
SmartPtr (T* p) :
p_ (p)
{
CheckingPolicy::Check (p_);
}
template <typename T1, typename PolicyT>
SmartPtr (SmartPtr<T1, PolicyT> & ptr,
// Enable moving from no checking pointer to any pointer
// or checking pointer to checking pointer.
// This makes it impossible to transfer checking to non-checking pointer.
typename boost::enable_if< boost::mpl::or_ <
boost::is_same<PolicyT, NoCheck>,
boost::is_same<PolicyT, CheckingPolicy> > >::type *dummy = NULL) :
p_ (ptr.get ())
{
CheckingPolicy::Check (p_);
ptr.release ();
}
~SmartPtr ()
{
delete p_;
p_ = NULL;
}
T *get () const
{
return p_;
}
T *release ()
{
T *result = p_;
p_ = NULL;
return result;
}
};
int main()
{
try
{
SmartPtr<int, NoCheck> p1 (NULL);
SmartPtr<int, EnforceNotNull> p2 = p1;
// SmartPtr<int, NoCheck> p3 = p2; // This will not compile.
}
catch (const NullPtrException &)
{
printf ("GOTCHA!!!\n");
}
}