4

Using C++11, I'd like to call a static member function template without qualifying it with the scope of its enclosing class:

struct Test {
    template<typename T>
    static bool Function(T x)
    { /* ... */ }
};

int x;
Test::Function(x); // I don't want to write this
Function(x); // I want to be able to write this instead

I can define another function with the same signature at global scope and forward the arguments, but I'd prefer a solution that doesn't force me to write another function. I'd also like to avoid using a macro.

This question is related: (using alias for static member functions?) but doesn't seem to cover the case of function templates.

Community
  • 1
  • 1
Prismatic
  • 3,338
  • 5
  • 36
  • 59

2 Answers2

4

Sure, you can alias the templated function if you want to do a little work with the using keyword first:

template<typename T>
using testfn = bool (*)(T);

and then create a pointer to the function with:

testfn<int> fnPointer = Test::Function;

and finally call it:

std::cout << boolalpha << fnPointer(x) << std::endl;

Live Demo

If you only ever want to bind to the case where T is int, you can do this:

using testfn = bool (*)(int);
//...
testfn fnPointer = Test::Function;
std::cout << boolalpha << fnPointer(x) << std::endl;

Live Demo 2

Edit: If you want a constexpr function pointer like in the accepted answer of the question you linked, that's a pretty simple extension:

constexpr auto yourFunction = &Test::Function<int>;
//...
std::cout << boolalpha << yourFunction(x) << std::endl;

Live Demo 3

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • Your first method requires me to specialize for 'int'. That isn't really syntactically equivalent to a straight call to Test::Function – Prismatic Feb 27 '15 at 23:16
  • @Pris: I wasn't sure your exact use case, so I tried to be general with the first method, and more specific with the second. – AndyG Feb 27 '15 at 23:36
  • In the simplest terms I want #define Function Test::Function without using a macro – Prismatic Feb 27 '15 at 23:45
  • @Pris: I'm not sure I follow. Are you looking for `constexpr` to appear somewhere? – AndyG Feb 28 '15 at 00:07
  • Regarding your latest update to the answer: The problem is you're specializing Test::Function for int. The example I gave is just a simple example. I want a generic solution for a static template member function and the goal is to be able to call said method without the enclosing class scope resolution. – Prismatic Feb 28 '15 at 00:15
  • @Pris: I think I understand what you are saying. Basically you want that `using` on your `struct` for member function `Function` works essentially the same way as if your `struct` was instead a `namespace`. However, I don't believe that what you want is possible, given your constraints. – AndyG Feb 28 '15 at 00:32
  • Thanks. This constexpr template function pointer worked for me (gotten from reading this): `template constexpr auto GetParam = &mlpack::CLI::GetParam;` .. then called with `bool sequential(GetParam("sequential"));` – matiu Dec 29 '18 at 20:08
0

I learned this playing with the @andyg answer (probably above mine), but it worked for me and it doesn't require putting a different alias for every template.

It requires c++14 or later though.

Step 1 - magical template alias:

template <typename T> constexpr auto funky1 = &Test::Function<T>;

Step 2 - lambda means you don't need to pass the template argument:

auto funky = [](auto in) { return funky1<decltype(in)>(in); };

full example

Also, inline full example:

#include <iostream>

struct Test {
  template <typename T> static bool Function(T x) { return true; }
};

// Magical template alias
template <typename T> constexpr auto funky1 = &Test::Function<T>;

// lambda means it'll infer the template parameters when calling
auto funky = [](auto in) { return funky1<decltype(in)>(in); };

int main() {
  int x = 0;

  // Just use the `funky1` version, but you have to specify the template parameters
  std::cout << "string: " << funky1<std::string>("I'm a string") << std::endl
            << "int: " << funky1<int>(42) << std::endl
            << "bool: " << funky1<bool>(true) << std::endl;

  // Use the `funky` version, where template parameters are inferred
  std::cout << "string: " << funky("I'm a string") << std::endl
            << "int: " << funky(42) << std::endl
            << "bool: " << funky(true) << std::endl;

  return 0;
}
matiu
  • 7,469
  • 4
  • 44
  • 48