1

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++

Zak
  • 12,213
  • 21
  • 59
  • 105
  • You already have a `StaticLibrary` datamember in `Environment`. What prevents you from making that public? – Henri Menke Aug 09 '17 at 21:13
  • The constraint that says I cannot. – Zak Aug 09 '17 at 21:13
  • But exposing a pointer to the private datamember is fine? I'm sorry, but this constraint is completely stupid. – Henri Menke Aug 09 '17 at 21:17
  • @HenriMenke The code above is the smallest sample I could create to demonstrate the compiler error. The larger body of code dictates the constraint. How stupid it may, or may not, be is not the point of this post. – Zak Aug 09 '17 at 21:18
  • 1
    Can you add a `int func() {sl->func();}` to the anonymous class? Can you have the anonymous class *inherit* from `Environment`? Without knowing where the constraint comes from it’s hard to answer the question. – Daniel H Aug 09 '17 at 21:26
  • Could your syntax change to `env.bar->func()`? – 1201ProgramAlarm Aug 09 '17 at 21:42
  • No, the syntax is necessary to match an externally defined API. – Zak Aug 09 '17 at 21:46
  • Unrelated: You don't need to declare functions inside the class body `inline`. They are `inline` by default. – Henri Menke Aug 09 '17 at 21:49

1 Answers1

0

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();
}
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • As stated as my #1 constraint, I cannot have a reference to `StaticLibrary` as a public member in `Environment`. – Zak Aug 09 '17 at 21:27
  • @Zak This was not in the question. According to the question »I cannot put StaticLibrary directly as a public member« which is perfectly fulfilled here. Please make your question more concise. – Henri Menke Aug 09 '17 at 21:29
  • You can’t have reference in addition to not having it a direct member? You didn’t say that part. – Daniel H Aug 09 '17 at 21:29
  • The syntax is paramount. I cannot use `env.bar().func()`. – Zak Aug 09 '17 at 21:34
  • I highlighted my actual question. I will not be able to modify the data structure, I need help forcing syntax. Suggestions on how to modify the data structure are unhelpful. – Zak Aug 09 '17 at 21:38
  • @Zak Then it is not possible. The `.` operator does not apply any conversions before lookup. So either `func()` is a member of `bar` or you have to make `bar` a reference (or public member) to `StaticLibrary`. Or, of course, you call the conversion explicitly as in `static_cast(env.bar).func();`. – Henri Menke Aug 09 '17 at 21:40
  • Can you site your source for, "there is no way around replicating the interface of StaticLibrary"? This may be the answer. Also, can you please remove the top two code bodies, so this "answer" would be more obvious? – Zak Aug 09 '17 at 21:40