class all {
public:
template <typename T>
all(T&& t)
: data_ptr(new derived<T>(std::forward<T>(t))) {
}
all()
: data_ptr(nullptr) {}
all(const all& o)
: data_ptr(o.clone()) {}
all(const all&& o)
: data_ptr(o.clone()) {}
all& operator=(const all& o) {
auto n = o.clone();
if (data_ptr != nullptr) {
delete data_ptr;
}
data_ptr = n;
return *this;
}
all& operator=(all&& a)
{
if (data_ptr == a.data_ptr)
return *this;
swap(data_ptr, a.data_ptr);
return *this;
}
~all() {
if (data_ptr != nullptr) {
delete data_ptr;
}
}
template <typename U>
bool is() const {
auto ret = dynamic_cast<derived<U>*>(data_ptr);
return ret != nullptr;
}
template<typename U> U& as(){
auto ret = dynamic_cast<derived<U>*>(data_ptr);
if (ret==nullptr){
throw std::runtime_error("type dynamic_cast error");
}
return ret->value;
}
template<typename U>operator U(){
return as<U>();
}
private:
struct base {
virtual base* clone() = 0;
virtual ~base(){};
};
template <typename T>
struct derived : public base {
template <typename U>
derived(U&& v)
: value(std::forward<U>(v)) {
}
T value;
base* clone() {
return new derived<T>(value);
}
};
base* data_ptr;
base* clone() const {
if (data_ptr == nullptr) {
return nullptr;
} else {
return data_ptr->clone();
}
}
};
cmake编译选项:
set (CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0 ")
测试用例如下:
int main(int argc, char const* argv[]) {
all at = 12;
cout << at.is<int>() << endl;
cout<<at.as<int>()<<endl;
cout<<int(at)<<endl;
return 0;
}
c++11,17都编译成功,但是c++11运行时抛出分段错误,c++17运行成功,为什么?我很沮丧,有人能帮我吗?
这里是完整的可复制的例子(不是最小的(。
all at = 12;
似乎转换序列是这样的:
- 使用构造函数
all::all<int>(int&&)
从右侧表达式构造临时对象 - 该临时对象用于初始化
at
- 由于临时
all
是非常数,因此模板构造函数比all(const all&&)
更匹配 - 因此,
all::all<all>(all&&)
被调用。这初始化了具有使用all::all<all>(all&&)
初始化的all
成员的all::derived<all>::derived
(因为这再次是比all::all(const all&&)
更好的匹配(,其调用了初始化all::derived<all>::derived
的all::all(const all&&)
,其调用all::all(const all&&)
。。。你能认出图案吗?递归永远不会结束。最终会出现堆栈溢出
在C++17中,at
直接从初始化程序初始化,而不涉及临时对象,因此不存在堆栈溢出。
一个简单的修复方法是添加一个移动构造函数:
all(all&& o) : data_ptr{std::exchange(o.data_ptr, nullptr)} {}
p.S.避免使用裸拥有指针,如data_ptr
。请改用智能指针,如std::unique_ptr
。