0

I've recently come across an interesting implementation of the SFINAE idiom and I'm having trouble working with the specialization classes. Let me explain with a simplified example. I'm utilizing 4 classes in my main function below-- 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;
}

Output:

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

Variant_ is a template class and derives from Base, which is an abstract class. English and Japanese are specialization classes and don't derive from anything.

Base:

class Base
{
public:
    Base(){}
    virtual ~Base(){}
protected:
    virtual void dispatch_say_hi()=0;
};

Variant_:

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

Ok, I lied. There is a fifth class has_f. It's a helper class to identify whether or not a function has been defined in the specializations. That's not where I'm having problems, but I've provided it just so this example can be compiled and run.

English:

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

Japanese:

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

This all compiles and runs.

Here's my question:

Lets say I modify 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;
    }
};

Now, when I try to run main(), I get a segmentation fault at MrRoboto.dispatch_say_hi(). It doesn't matter if the member variable is private or public, or if it is an int or string. I get a segmentation fault whenever I try to access any member variables. Why does this happen?

It's interesting to note that if I define another function, I can call it like so:

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

The output of this is:

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

Any ideas?

uclatommy
  • 305
  • 4
  • 11

1 Answers1

3

You have a unique_ptr<impl> that is never set, so it stays at its initial default value, which is nullptr. It worked before because you were not anything from Japanese except functions (note : you have undefined behavior for dereferencing the null pointer, even if in your case most implementations will just work).

Note that what you did is called "Policy pattern". It is sometimes very useful, and can be interesting, however please note that the big downside of this pattern is the lack of interface - there is nothing that tell a user what functions to implement, so they have to look in the code.

Synxis
  • 9,236
  • 2
  • 42
  • 64
  • This was it. Once I initialized `impl_` from `Variant_`, it worked as expected. Thanks for naming the pattern! I'll have to read up on it. – uclatommy Oct 06 '15 at 14:49