C++ SFINAE使用模板、专门化和实现类型擦除

C++ SFINAE使用模板、专门化和实现类型擦除,c++,segmentation-fault,sfinae,specialization,C++,Segmentation Fault,Sfinae,Specialization,我最近遇到了一个有趣的SFINAE习语实现,我在使用专门化类时遇到了问题。让我用一个简单的例子来解释。我在下面的主函数中使用了4个类--Base,Variant,English,Japanese #include <iostream> #include <memory> int main() { Variant_<English> MrRobert; Variant_<Japanese> MrRoboto; std::c

我最近遇到了一个有趣的SFINAE习语实现,我在使用专门化类时遇到了问题。让我用一个简单的例子来解释。我在下面的主函数中使用了4个类--
Base
Variant
English
Japanese

#include <iostream>
#include <memory>

int main() {
    Variant_<English> MrRobert;
    Variant_<Japanese> MrRoboto;

    std::cout << "Mr. Robert: ";
    MrRobert.dispatch_say_hi();

    std::cout << "Mr. Roboto: ";
    MrRoboto.dispatch_say_hi();

    return 0;
}
class Japanese
{
private:
    std::string something_else;
public:
    void say_hi(){
        std::cout<<"Konnichiwa Sekkai!";
        something_else = " bleep bloop"; //segfault!
        std::cout<<something_else<<std::endl;
    }
};
Variant\uu
是一个模板类,它派生自
Base
,后者是一个抽象类<代码>英语和
日语
都是专业化课程,没有任何来源

基础:

Mr. Robert: Hello World!
Mr. Roboto: Konnichiwa Sekkai!
class Base
{
public:
    Base(){}
    virtual ~Base(){}
protected:
    virtual void dispatch_say_hi()=0;
};
template<class T>
struct has_f
{
    typedef char yes;
    typedef char (&no)[2];
    template<class U>
    static yes test_say_hi(__typeof__(&U::say_hi));
    template<class U>
    static no test_say_hi(...);
    static const int say_hi = sizeof(test_say_hi<T>(0)) == sizeof(yes);
};

template<class Impl>
class Variant_: private Base
{
    std::unique_ptr<Impl> impl_;
public:
    template<int I> struct int_{};
    typedef int_<0> not_implemented;
    typedef int_<1> implemented;

    void say_hi(not_implemented){
        std::cout << "..." << std::endl;
    }
    void say_hi(implemented){
        impl_->say_hi();
    }
    void dispatch_say_hi(){
        say_hi(int_<has_f<Impl>::say_hi>());
    }
};
class English
{
public:
    void say_hi(){
        std::cout<<"Hello World!"<< std::endl;
    }
};
class Japanese
{
public:
    void say_hi(){
        std::cout<<"Konnichiwa Sekkai!"<<std::endl;
    }
};
变体:

Mr. Robert: Hello World!
Mr. Roboto: Konnichiwa Sekkai!
class Base
{
public:
    Base(){}
    virtual ~Base(){}
protected:
    virtual void dispatch_say_hi()=0;
};
template<class T>
struct has_f
{
    typedef char yes;
    typedef char (&no)[2];
    template<class U>
    static yes test_say_hi(__typeof__(&U::say_hi));
    template<class U>
    static no test_say_hi(...);
    static const int say_hi = sizeof(test_say_hi<T>(0)) == sizeof(yes);
};

template<class Impl>
class Variant_: private Base
{
    std::unique_ptr<Impl> impl_;
public:
    template<int I> struct int_{};
    typedef int_<0> not_implemented;
    typedef int_<1> implemented;

    void say_hi(not_implemented){
        std::cout << "..." << std::endl;
    }
    void say_hi(implemented){
        impl_->say_hi();
    }
    void dispatch_say_hi(){
        say_hi(int_<has_f<Impl>::say_hi>());
    }
};
class English
{
public:
    void say_hi(){
        std::cout<<"Hello World!"<< std::endl;
    }
};
class Japanese
{
public:
    void say_hi(){
        std::cout<<"Konnichiwa Sekkai!"<<std::endl;
    }
};
日语:

Mr. Robert: Hello World!
Mr. Roboto: Konnichiwa Sekkai!
class Base
{
public:
    Base(){}
    virtual ~Base(){}
protected:
    virtual void dispatch_say_hi()=0;
};
template<class T>
struct has_f
{
    typedef char yes;
    typedef char (&no)[2];
    template<class U>
    static yes test_say_hi(__typeof__(&U::say_hi));
    template<class U>
    static no test_say_hi(...);
    static const int say_hi = sizeof(test_say_hi<T>(0)) == sizeof(yes);
};

template<class Impl>
class Variant_: private Base
{
    std::unique_ptr<Impl> impl_;
public:
    template<int I> struct int_{};
    typedef int_<0> not_implemented;
    typedef int_<1> implemented;

    void say_hi(not_implemented){
        std::cout << "..." << std::endl;
    }
    void say_hi(implemented){
        impl_->say_hi();
    }
    void dispatch_say_hi(){
        say_hi(int_<has_f<Impl>::say_hi>());
    }
};
class English
{
public:
    void say_hi(){
        std::cout<<"Hello World!"<< std::endl;
    }
};
class Japanese
{
public:
    void say_hi(){
        std::cout<<"Konnichiwa Sekkai!"<<std::endl;
    }
};
现在,当我尝试运行
main()
时,我在
MrRoboto.dispatch\u say\u hi()
上遇到了一个分段错误。成员变量是私有的还是公共的,或者是int或string,都无关紧要。每当我试图访问任何成员变量时,就会出现分段错误。为什么会发生这种情况

有趣的是,如果我定义了另一个函数,我可以这样调用它:

class Japanese
{
public:
    void say_hi(){
        std::cout<<"Konnichiwa Sekkai!";
        say_something_else();
        std::cout<<std::endl;
    }

    void say_something_else()
    {
        std::cout<<" bleep bloop";
    }
};

有什么想法吗?

您有一个从未设置过的
唯一的\u ptr
,因此它保持初始默认值,即
nullptr
。它以前工作过,因为除了函数之外,您不是来自
日语的任何东西(注意:您有取消引用空指针的未定义行为,即使在您的情况下,大多数实现都可以工作)


请注意,您所做的被称为“策略模式”。它有时非常有用,也可能很有趣,但是请注意,这种模式的最大缺点是缺乏界面-没有任何东西可以告诉用户要实现什么函数,因此他们必须查看代码。

您有一个从未设置的
唯一\u ptr
,因此它保持在初始默认值,这是
nullptr
。它以前工作过,因为除了函数之外,您不是来自
日语的任何东西(注意:您有取消引用空指针的未定义行为,即使在您的情况下,大多数实现都可以工作)


请注意,您所做的被称为“策略模式”。它有时非常有用,也可能很有趣,但是请注意,这种模式的最大缺点是缺乏界面-没有任何东西可以告诉用户要实现什么函数,因此他们必须查看代码。

您有一个从未设置的
唯一\u ptr
,因此它保持在初始默认值,这是
nullptr
。它以前工作过,因为除了函数之外,您不是来自
日语的任何东西(注意:您有取消引用空指针的未定义行为,即使在您的情况下,大多数实现都可以工作)


请注意,您所做的被称为“策略模式”。它有时非常有用,也可能很有趣,但是请注意,这种模式的最大缺点是缺乏界面-没有任何东西可以告诉用户要实现什么函数,因此他们必须查看代码。

您有一个从未设置的
唯一\u ptr
,因此它保持在初始默认值,这是
nullptr
。它以前工作过,因为除了函数之外,您不是来自
日语的任何东西(注意:您有取消引用空指针的未定义行为,即使在您的情况下,大多数实现都可以工作)


请注意,您所做的被称为“策略模式”。它有时非常有用,也可能很有趣,但是请注意,这种模式的最大缺点是缺乏界面-没有任何东西可以告诉用户要实现什么功能,因此,他们必须查看代码。

我确信
std::unique\u ptr impl\u
没有初始化我确信
std::unique\u ptr impl\u
没有初始化我确信
std::unique\u ptr impl\u
没有初始化我确信
std::unique\u ptr impl\u
没有初始化就是这样。一旦我从
Variant
初始化了
impl
,它就按预期工作了。感谢您命名的模式!我得好好读一读,就是这样。一旦我从
Variant
初始化了
impl
,它就按预期工作了。感谢您命名的模式!我得好好读一读,就是这样。一旦我从
Variant
初始化了
impl
,它就按预期工作了。感谢您命名的模式!我得好好读一读,就是这样。一旦我从
Variant
初始化了
impl
,它就按预期工作了。感谢您命名的模式!我得仔细阅读一下。