18

Has anyone ever used pointers/references/pointer-to-member (non-type) template parameters?
I'm not aware of any (sane/real-world) scenario in which that C++ feature should be used as a best-practice.

Demonstation of the feature (for pointers):

template <int* Pointer> struct SomeStruct {};
int someGlobal = 5;
SomeStruct<&someGlobal> someStruct; // legal c++ code, what's the use?

Any enlightenment will be much appreciated!

infokiller
  • 3,086
  • 1
  • 21
  • 28

5 Answers5

13

Pointer-to-function:

Pointer-to-member-function and pointer-to-function non-type parameters are really useful for some delegates. It allows you to make really fast delegates.

Ex:

#include <iostream>
struct CallIntDelegate
{
    virtual void operator()(int i) const = 0;
};

template<typename O, void (O::*func)(int)>
struct IntCaller : public CallIntDelegate
{
    IntCaller(O* obj) : object(obj) {}
    void operator()(int i) const
    {
        // This line can easily optimized by the compiler
        // in object->func(i) (= normal function call, not pointer-to-member call)
        // Pointer-to-member calls are slower than regular function calls
        (object->*func)(i);
    }
private:
    O* object;
};

void set(const CallIntDelegate& setValue)
{
    setValue(42);
}

class test
{
public:
    void printAnswer(int i)
    {
        std::cout << "The answer is " << 2 * i << "\n";
    }
};

int main()
{
    test obj;
    set(IntCaller<test,&test::printAnswer>(&obj));
}

Live example here.

Pointer-to-data:

You can use such non-type parameters to extend the visibility of a variable.

For example, if you were coding a reflexion library (which might very useful for scripting), using a macro to let the user declare his classes for the library, you might want to store all data in a complex structure (which may change over time), and want some handle to use it.

Example:

#include <iostream>
#include <memory>

struct complex_struct
{
    void (*doSmth)();
};

struct complex_struct_handle
{
    // functions
    virtual void doSmth() = 0;
};

template<complex_struct* S>
struct csh_imp : public complex_struct_handle
{
    // implement function using S
    void doSmth()
    {
        // Optimization: simple pointer-to-member call,
        // instead of:
        // retrieve pointer-to-member, then call it.
        // And I think it can even be more optimized by the compiler.
        S->doSmth();
    }
};

class test
{
    public:
        /* This function is generated by some macros
           The static variable is not made at class scope
           because the initialization of static class variables
           have to be done at namespace scope.

           IE:
               class blah
               {
                   SOME_MACRO(params)
               };
           instead of:
               class blah
               {
                   SOME_MACRO1(params)
               };
               SOME_MACRO2(blah,other_params);

           The pointer-to-data template parameter allows the variable
           to be used outside of the function.
        */
        std::auto_ptr<complex_struct_handle> getHandle() const
        {
            static complex_struct myStruct = { &test::print };
            return std::auto_ptr<complex_struct_handle>(new csh_imp<&myStruct>());
        }
        static void print()
        {
            std::cout << "print 42!\n";
        }
};

int main()
{
    test obj;
    obj.getHandle()->doSmth();
}

Sorry for the auto_ptr, shared_ptr is available neither on Codepad nor Ideone. Live example.

Synxis
  • 9,236
  • 2
  • 42
  • 64
  • 3
    I actually used the pointer-to-member variant to implement a 'member-foreach' sort of thing. – xtofl Nov 04 '12 at 17:46
  • 1
    Personnally I use them for a 'signal-slot' module in a library (SPARK Particle Engine), it's a really powerful part of C++. – Synxis Nov 04 '12 at 17:50
  • Regarding the pointer-to-function example, would there be a way to keep the pointer to printAnswer within an object and then give this object to the set function to achieve the same result? – ALOToverflow Apr 12 '13 at 16:40
  • @ALOToverflow Yes, but you would also have to pass a pointer to the object. The tricky part is when this function does not know the type of the object (for example, the function is in a library, the object is from you), as calling a pointer-to-function requires you to know the type of the object. Thus the delegate showed can solve this problem. – Synxis Apr 12 '13 at 18:24
8

The case for a pointer to member is substantially different from pointers to data or references.

Pointer to members as template parameters can be useful if you want to specify a member function to call (or a data member to access) but you don't want to put the objects in a specific hierarchy (otherwise a virtual method is normally enough).

For example:

#include <stdio.h>

struct Button
{
    virtual ~Button() {}
    virtual void click() = 0;
};

template<class Receiver, void (Receiver::*action)()>
struct GuiButton : Button
{
    Receiver *receiver;
    GuiButton(Receiver *receiver) : receiver(receiver) { }
    void click() { (receiver->*action)(); }
};

// Note that Foo knows nothing about the gui library    
struct Foo
{
    void Action1() { puts("Action 1\n"); }
};

int main()
{
    Foo foo;
    Button *btn = new GuiButton<Foo, &Foo::Action1>(&foo);
    btn->click();
    return 0;
}

Pointers or references to global objects can be useful if you don't want to pay an extra runtime price for the access because the template instantiation will access the specified object using a constant (load-time resolved) address and not an indirect access like it would happen using a regular pointer or reference. The price to pay is however a new template instantiation for each object and indeed it's hard to think to a real world case in which this could be useful.

6502
  • 112,025
  • 15
  • 165
  • 265
4

The Performance TR has a few example where non-type templates are used to abstract how the hardware is accessed (the hardware stuff starts at page 90; uses of pointers as template arguments are, e.g., on page 113). For example, memory mapped I/O registered would use a fixed pointer to the hardware area. Although I haven't ever used it myself (I only showed Jan Kristofferson how to do it) I'm pretty sure that it is used for development of some embedded devices.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
4

It is common to use pointer template arguments to leverage SFINAE. This is especially useful if you have two similar overloads which you couldn't use std::enable_if default arguments for, as they would cause a redefinition error.

This code would cause a redefinition error:

template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo (T x)
{
    cout << "integral"; 
}

template <typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void foo (T x)
{
    cout << "floating";
}

But this code, which utilises the fact that valid std::enable_if_t constructs collapse to void by default, is fine:

                      // This will become void* = nullptr
template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo (T x)
{
    cout << "integral"; 
}

template <typename T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
void foo (T x)
{
    cout << "floating";
}
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
2

Occasionally you need to supply a callback function having a particular signature as a function pointer (e.g. void (*)(int)), but the function you want to supply takes different (though compatible) parameters (e.g. double my_callback(double x)), so you can't pass its address directly. In addition, you might want to do some work before and after calling the function.

It's easy enough to write a class template that tucks away the function pointer and then calls it from inside its operator()() or some other member function, but this doesn't provide a way to extract a regular function pointer, since the entity being called still requires the this pointer to find the callback function.

You can solve this problem in an elegant and typesafe way by building an adaptor that, given an input function, produces a customised static member function (which, like a regular function and unlike a non-static member function, can have its address taken and used for a function pointer). A function-pointer template parameter is needed to embed knowledge of the callback function into the static member function. The technique is demonstrated here.

Community
  • 1
  • 1
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169