0

Consider the following non class template that has a template variable and uses template aliasing and auto type deduction.

template<typename T>
using Type = T;

using TypeA = Type<int>;
using TypeB = Type<double>;

class Foo {
private:
    template<typename T>
    static Type<T> type_;
public:
    template<typename T>
    explicit Foo( Type<T> type ) { type_<T> = type; }

    // non static member
    template<typename T>
    auto bar() { return type_<T>; }

    // static member
    template<typename T>
    static auto bar(T _x_ = 0) { return type_<T>; }
};

And the program that uses it:

// has to be defined in some cpp file.
template<typename T>
Type<T> Foo::type_;

int main() {
     TypeA a{ 7 };
     TypeB b{ 3.41 };

     Foo f1( a );
     Foo f2( b );

     auto x = Foo::bar<TypeA>();
     auto y = Foo::bar<TypeB>();

     std::cout << "static auto f1: " << x << '\n';
     std::cout << "static auto f2: " << y << '\n';

     std::cout << "member f1: " << f1.bar<TypeA>() << '\n';
     std::cout << "member f2: " << f2.bar<TypeB>() << '\n';

     return 0;
};

Output

static auto f1: 7
static auto f2: 3.41
member f1: 7
member f2: 3.41

In the class declaration; I'm using a parameter T in the static version and defaulting it to 0 so that this can be called without any parameters. If this is not added then one would not be able to overload a static and a non static member function that has no arguments or the same arguments for its parameter list.

Would this be considered a quick fix or a hack, or is this a possible way to be able to provide the same type of interface for both a static and non static member function with the same name and functionality?

The function argument or parameter is a dummy argument as does absolutely nothing to the internal value.

After coming back and reading this again I can see were some of the confusion was coming from and I left out the facts that this pertains more to the use of variable templates and being able to access them.

So I think the real question should of been: Concerning variable template members and that they are required to be static, what is the preferred way to access them through a member function: via static or non static, or is there no preference and that choice is left up to the programmer?

One other last thing; are there any unforeseen issues that may lead to future consequences with this type of design pattern - interface?

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • "You're in a maze of twisty little passages, all alike." – Pete Becker Jul 20 '19 at 22:15
  • 1
    A static member function can be invoked using the `f1.bar()` syntax. No need to declare a non-static version (as long as you don't want to create a pointer-to-member to the function.) – cpplearner Jul 20 '19 at 22:17
  • I don't even understand what you're doing here. The return type is going to be `Type>` or `Type>`. Is that what you even want? If you do, that seems very strange. – Omnifarious Jul 20 '19 at 22:45
  • Which compiler are you using? I'm getting "ambiguous call" type errors when I try to compile it. – 1201ProgramAlarm Jul 20 '19 at 23:35
  • Possible duplicate of [C++ Static member method call on class instance](https://stackoverflow.com/questions/325555/c-static-member-method-call-on-class-instance). Or possibly not, depending on what the intended use of this "same type of interface" is. – JaMiT Jul 21 '19 at 00:50
  • As a side note; I've been aware of the concepts of template aliases and template variables but never used them before. This was just experimental practice. Getting use to the syntax and how to properly implement them. When I started to work with the variable template within a class, the compiler was forcing me to declare it as a static member. I was able to write functions that would accesses it either via static or non static which lead me to the above. I just wanted clarity on the reasoning. – Francis Cugler Jul 21 '19 at 06:22
  • I think the way I asked my question was a bit misleading as I did not specify that this was mostly in regards to the use of template aliasing and template variables. I has more to do with them then it does static vs non static functions and I was just able to produce a version of both to do the same thing but giving either one of them an overloaded defaulted dummy argument that does nothing internally. I never did mention in the question that `T _x_ = 0` within the declaration of the function does absolutely nothing to the internal values. It is just a dummy argument. – Francis Cugler Jul 21 '19 at 06:36
  • @JaMiT Just to access the internal template variable member and return the current value at some given point in time... these functions do not modify the value. – Francis Cugler Jul 21 '19 at 06:47
  • @1201ProgramAlarm I'm using Visual Studio 2017 compiled as C++17 – Francis Cugler Jul 21 '19 at 06:51
  • @Omnifarious I'm starting to experiment with the use of `Variable Templates` and `Template Aliasing` as I have never really used them, so this was practice code just to get a feel for the proper syntax and usages of them. I'm just looking out for the corner cases, gotchas, etc. – Francis Cugler Jul 21 '19 at 06:55
  • @FrancisCugler Your modified question has nothing to do with templates anymore. It's just a question about whether or nat an accessor for a `static` data member should also be `static`. In that case, the duplicate is probably [Advantage of using a static member function instead of an equivalent non-static member function?](https://stackoverflow.com/questions/2748962/advantage-of-using-a-static-member-function-instead-of-an-equivalent-non-static) – JaMiT Jul 21 '19 at 21:44

1 Answers1

2

Is this considered a quick fix or a hack, or is this the proper way to be able to provide the same type of interface for both a static and non static member function of the same name?

There is no proper way to accomplish an improper goal. Besides which, your version does not provide the same interface. The non-static version requires an explicit template argument, whereas the static version can use deduction, as in f1.bar(1). I'm not sure I'd recommend using the deduction in this case (because the code is more cryptic), but the possibility is provided. Your improper goal is not even met.

If the functions have the same functionally (as in your example), then the non-static version is pointless overhead. Provide just the static version, and if someone wants to call it from an object, that's A-OK.

If the functions do not have the same functionally (maybe your example was oversimplified?), then giving them the same name is a Bad Idea. This includes the case where the non-static version can return different values depending on *this. At the very least in this case, the static version should be renamed to something like bar_no_object() to distinguish it from the version that depends on the object.

One other last thing; are there any unforeseen issues that may lead to future consequences with this type of design pattern - interface?

Well, basically you are setting yourself up for a load of confusion. Everyone else will expect Foo::bar() and Foo{}.bar() to invoke the same (static) function, and you are trying to break that.

Pay attention to your compiler's messages. This expectation of everyone else is the reason you were not able "to overload a static and a non static member function that has no arguments or the same arguments for its parameter list." You tried to create ambiguity and the compiler stopped you. With good reason. Before asking if your workaround is valid, perhaps you should have asked for the reason the compiler stopped you?

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • I understand why the compiler prevented me from overloading a static and non static function with the same signatures. I was just experimenting with variable templates and template alias and when I started to add the variable template as a class member it was forcing me to declare the variable as static. I was able to write an access function to retrieve the value by either static or non static versions. I then figured out that if I gave the static version a `dummy` argument that does nothing internally, then I could retrieve the value from either or both functions. – Francis Cugler Jul 21 '19 at 06:30
  • 1
    @FrancisCugler In other words, you discovered that the non-static version could do everything the static version could, but could be used in fewer contexts (a strict subset of the contexts where the static version can be used). It is strictly inferior to the static version. There is ***no** reason to keep it*. Yet you wanted to keep it. The result was messy code with no benefit. Don't do that. – JaMiT Jul 21 '19 at 21:31