C++ Utilizing dot syntax to call function on "Property" (unnamed class)

1.2k views Asked by At

Goal

My objective is to call StaticLibrary::func() from the property (unnamed class) on Environment using the dot syntax.

For example:

env.bar.func();

I have been able to achieve static_cast<StaticLibrary>(env.bar).func();, which is close, but the syntax is still too cumbersome.

Question

Can the static cast be inferred, or can I overload some operator to get the desired syntax?

NOTE: I have a constraint that I cannot put StaticLibrary directly as a public member of the Environment class (object, reference or pointer).

Error

I currently get the error (which I understand, but pasted here for completeness):

unnamedDotSyntax.cpp: In function ‘int main()’:
unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
     env.bar.func();
             ^

Code

The example below is the most distilled version of the code I can offer.

#include <iostream>

class StaticLibrary {
  public:
    int func (void) {
        std::cout << "called " << __FUNCTION__ << std::endl;
    }
};

class Environment {
  public:
    Environment (void) {
        bar.sl = &sl;
    }

    inline
    int foo (void) {
        std::cout << "called " << __FUNCTION__ << std::endl;
    }

    class {
        friend Environment;
      public:
        operator StaticLibrary & (void) {
            return *sl;
        }
      private:
        StaticLibrary * sl;
    } bar;

  private:
    StaticLibrary sl;
};

int main (void) {
    Environment env;
    env.foo();

    // Works
    StaticLibrary sl = env.bar;
    sl.func();

    // Works, but the syntax is too cumbersome. Can the static cast be inferred somehow?
    static_cast<StaticLibrary>(env.bar).func();

    // unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
    //      env.bar.func();
    env.bar.func();
}

NOTE: This must be GCC compatible not Microsoft VC++

1

There are 1 answers

7
Henri Menke On

For the nested class there is no way around replicating the interface of StaticLibrary, because the member access operator (.) does not apply any conversions. So to call func() on bar you need to have a member function func() in bar. It does not suffice if bar converts to something that has a member function func() (because this could be ambiguous).

That is to say, you could wrap the interface of StaticLibrary inside bar by having a delegating member function int func() { return sl.func(); } or you make bar a public data member of type StaticLibrary (which was forbidden by your constraint).

Here I gave the nested class a name because it makes the errors more readable and I store a reference rather than a pointer because I like value semantics.

#include <iostream>

class StaticLibrary {
public:
  int func() {
    std::cout << "called " << __FUNCTION__ << std::endl;
    return 0;
  }
};

class Environment {
private:
  StaticLibrary sl;
public:

  class Bar {
    friend Environment;
    StaticLibrary& sl;
  public:
    explicit Bar(StaticLibrary& _sl) : sl(_sl) {};
    operator StaticLibrary& () { return sl; }
    int func() { return sl.func(); }
  } bar;

  Environment() : sl{}, bar{sl} {};

  int foo() {
    std::cout << "called " << __FUNCTION__ << std::endl;
    return 0;
  }
};

int main (void) {
    Environment env;
    env.foo();

    // Works
    StaticLibrary sl = env.bar;
    sl.func();

    // Works, but the syntax is too cumbersome. Can the static cast be inferred somehow?
    static_cast<StaticLibrary>(env.bar).func();

    // unnamedDotSyntax.cpp:48:13: error: ‘class Environment::<anonymous>’ has no member named ‘func’
    //      env.bar.func();
    env.bar.func();
}