考慮一個基於策略的智能指針類Ptr,只有一個策略會阻止將它解除引用到NULL狀態(以某種方式)。讓我們考慮這樣的2種策略:在基於策略的類中保留構造的隱含性
NotNull
NoChecking
由於NotNull
政策更嚴格,我們希望允許隱式轉換從Ptr< T, NoChecking >
到Ptr< T, NotNull >
,而不是相反方向。爲了安全起見,這必須是明確的。請看看下面的實現:
#include <iostream>
#include <type_traits>
#include <typeinfo>
struct NoChecking;
struct NotNull;
struct NoChecking{
NoChecking() = default;
NoChecking(const NoChecking&) = default;
explicit NoChecking(const NotNull&)
{ std::cout << "explicit conversion constructor of NoChecking" << std::endl; }
protected:
~NoChecking() {} //defaulting the destructor in GCC 4.8.1 makes it public somehow :o
};
struct NotNull{
NotNull() = default;
NotNull(const NotNull&) = default;
NotNull(const NoChecking&)
{ std::cout << "explicit conversion constructor of NotNull" << std::endl; }
protected:
~NotNull() {}
};
template<
typename T,
class safety_policy
> class Ptr
: public safety_policy
{
private:
T* pointee_;
public:
template <
typename f_T,
class f_safety_policy
> friend class Ptr; //we need to access the pointee_ of other policies when converting
//so we befriend all specializations of Ptr
//implicit conversion operator
template<
class target_safety
> operator Ptr<T, target_safety>() const {
std::cout << "implicit conversion operator of " << typeid(*this).name() << std::endl;
static_assert(std::is_convertible<const safety_policy&, const target_safety&>::value,
//What is the condition to check? This requires constructibility
"Safety policy of *this is not implicitly convertible to target's safety policy.");
//calls the explicit conversion constructor of the target type
return Ptr< T, target_safety >(*this);
}
//explicit conversion constructor
template<
class target_safety
> explicit Ptr(const Ptr<T, target_safety>& other)
: safety_policy(other), //this is an explicit constructor call and will call explicit constructors when we make Ptr() constructor implicit!
pointee_(other.pointee_)
{ std::cout << "explicit Ptr constructor of " << typeid(*this).name() << std::endl; }
Ptr() = default;
};
//also binds to temporaries from conversion operators
void test_noChecking(const Ptr< int, NoChecking >&)
{ }
void test_notNull(const Ptr< int, NotNull >&)
{ }
int main()
{
Ptr< int, NotNull > notNullPtr; //enforcing not null value not implemented for clarity
Ptr< int, NoChecking > fastPtr(notNullPtr); //OK - calling explicit constructor and NotNull is explicitly convertible to NoChecking
test_notNull (fastPtr ); //should be OK - NoChecking is implictly convertible to NotNull
test_noChecking (notNullPtr); //should be ERROR - NotNull is explicitly convertible to NoChecking
return 0;
}
的代碼時,在兩個方向上,這意味着std::is_convertible
失敗,即使類具有兼容的構造函數隱式轉換上面的失敗。問題是:
- 構造函數重載不能簡單地通過顯式關鍵字不同,所以我們需要在宿主類中顯式構造函數和隱式轉換運算符(反之亦然)。
- 顯式構造函數更好,因爲任何構造函數都會從初始化列表中調用顯式構造函數,即使它本身是隱式的。
- 隱式轉換運算符不能創建策略類型的對象,因爲它們的析構函數受到保護。這就是爲什麼
std::is_convertible
不應該失敗,這也是爲什麼我們不能在轉換運算符中使用類似boost::implicit_cast< const target_policy& >(*this)
的原因,因爲它會創建一個臨時策略對象,這是禁止的。
至於明顯的解決方案不是最優的,我認爲:
- 使策略析構函數公共 - 和風險UB鑄造時PTR *政策*和刪除呢?在提供的例子中這不太可能,但是在現實世界的應用中是可能的。
- 使析構函數公開並使用受保護的繼承 - 我需要公共繼承提供的豐富接口。
的問題是:
是否有另一個不創建這些類型的對象靜態測試的隱式構造函數的存在從一種類型?
或者:
從主機類的構造函數的構造函數調用的政策時,如何保持隱建設的信息?
編輯:
我只是意識到第二個問題可以用這樣一個私人的,隱含的國旗的構造很容易回答:但是
#include <iostream>
#include <type_traits>
#include <typeinfo>
struct implicit_flag {};
struct NoChecking;
struct NotNull;
struct NoChecking{
NoChecking() = default;
NoChecking(const NoChecking&) = default;
protected:
explicit NoChecking(const NotNull&)
{ std::cout << "explicit conversion constructor of NoChecking" << std::endl; }
~NoChecking() {} //defaulting the destructor in GCC 4.8.1 makes it public somehow :o
};
struct NotNull{
NotNull() = default;
NotNull(const NotNull&) = default;
protected:
NotNull(implicit_flag, const NoChecking&)
{ std::cout << "explicit conversion constructor of NotNull" << std::endl; }
~NotNull() {}
};
template<
typename T,
class safety_policy
> class Ptr
: public safety_policy
{
private:
T* pointee_;
public:
template <
typename f_T,
class f_safety_policy
> friend class Ptr; //we need to access the pointee_ of other policies when converting
//so we befriend all specializations of Ptr
//implicit conversion operator
template<
class target_safety
> operator Ptr<T, target_safety>() const {
std::cout << "implicit conversion operator of " << typeid(*this).name() << std::endl;
/*static_assert(std::is_convertible<const safety_policy&, const target_safety&>::value, //What is the condition to check? This requires constructibility
"Safety policy of *this is not implicitly convertible to target's safety policy.");*/
//calls the explicit conversion constructor of the target type
return Ptr< T, target_safety >(implicit_flag(), *this);
}
//explicit conversion constructor
template<
class target_safety
> explicit Ptr(const Ptr<T, target_safety>& other)
: safety_policy(other), //this is an explicit constructor call and will not preserve the implicity of conversion!
pointee_(other.pointee_)
{ std::cout << "explicit Ptr constructor of " << typeid(*this).name() << std::endl; }
private:
//internal implicit-flagged constructor caller that is called from implicit conversion operator
template<
class target_safety
> Ptr(implicit_flag implicit, const Ptr<T, target_safety>& other)
: safety_policy(implicit, other), //this constructor is required in the policy
pointee_(other.pointee_)
{ std::cout << "explicit Ptr constructor of " << typeid(*this).name() << std::endl; }
public:
Ptr() = default;
};
//also binds to temporaries from conversion operators
void test_noChecking(const Ptr< int, NoChecking >&)
{ }
void test_notNull(const Ptr< int, NotNull >&)
{ }
int main()
{
Ptr< int, NotNull > notNullPtr; //enforcing not null value not implemented for clarity
Ptr< int, NoChecking > fastPtr(notNullPtr); //OK - calling explicit constructor and NotNull is explicitly convertible to NoChecking
test_notNull (fastPtr ); //should be OK - NoChecking is implictly convertible to NotNull
test_noChecking (notNullPtr); //should be ERROR - NotNull is explicitly convertible to NoChecking
return 0;
}
的錯誤是不太可讀,我們對這些政策提出了不必要的要求,所以對第一個問題的回答更可取。
'的std :: is_constructible :: value',反之亦然。由於私有析構函數,構造策略類型的對象是不可能的,所以我不確定這有什麼幫助。迷人的把戲,但。我相信我會在別的地方使用它。 –
tsuki
2014-08-27 11:44:43