【问题标题】:SFINAE using templates, specialization, and achieving type erasureSFINAE 使用模板,专业化,实现类型擦除
【发布时间】:2015-10-06 07:09:25
【问题描述】:

我最近遇到了一个有趣的 SFINAE 习语实现,但我在使用专业化课程时遇到了麻烦。让我用一个简化的例子来解释。我在下面的主要功能中使用了 4 个类——BaseVariant_EnglishJapanese

#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;
}

输出:

Mr. Robert: Hello World!
Mr. Roboto: Konnichiwa Sekkai!

Variant_ 是一个模板类,它派生自一个抽象类BaseEnglishJapanese 是特化类,不派生自任何东西。

基地:

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>());
    }
};

好吧,我撒谎了。有第五课has_f。它是一个帮助类,用于识别是否在特化中定义了函数。这不是我遇到问题的地方,但我提供它只是为了让这个示例可以编译和运行。

英语:

class English
{
public:
    void say_hi(){
        std::cout<<"Hello World!"<< std::endl;
    }
};

日语:

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

这一切都编译并运行。

这是我的问题:

假设我修改了Japanese

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;
    }
};

现在,当我尝试运行 main() 时,MrRoboto.dispatch_say_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";
    }
};

这个的输出是:

Mr. Robert: Hello World!
Mr. Roboto: Konnichiwa Sekkai! bleep bloop

有什么想法吗?

【问题讨论】:

  • 我确定std::unique_ptr&lt;Impl&gt; impl_ 没有初始化

标签: c++ segmentation-fault sfinae specialization


【解决方案1】:

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

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

【讨论】:

  • 就是这样。一旦我从Variant_ 初始化impl_,它就会按预期工作。感谢您命名模式!我将不得不阅读它。
猜你喜欢
  • 2012-10-03
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多