2

I am targeting c++11 (with g++ version 4.7) and c++0x (with icpc 12.something, the intel c++ compiler). I might use clang some day.

I have the following data structure:

template<typename mydata_t>
struct mystruct {
    template<typename mycmp_t,
             int (*cmp)(const mydata_t &, const mycmp_t &)
             >
    void insert(const mydata_t &value, const mycmp_t &key) {
        // use key to search for where to put value, by calling
        // cmp(item_already_in_mystruct, key);
    }
};

The idea is that the client could do

int double_double_compare_fun(const double &d1, const double &d2) { ...; }
int double_int_compare_fun(const double &d, const int &i) { ...; }
int main(void) {
    struct mystruct<double> s;
    s.insert<double, double_double_compare_fun>(4.2, 4.2);
    s.insert<int, double_int_compare_fun>(6.2, 6);
}

or something less silly.

I currently have this working and it's not too crazy. But I'm hoping I can do better.

double_double_compare_fun and double_int_compare_fun already name the type of the second parameter. So in my head, I imagine there's some way to get the compiler to infer the first template argument to insert. I'd love to be able to say

s.insert<double_double_compare_fun>(4.2, 4.2);
s.insert<double_int_compare_fun>(6.2, 6);

and have mycmp_t inferred either from the signature of cmp or from the type of key. Alternatively, I'd be happy if mycmp_t could default to the type of the second parameter to cmp.

I tried variations on this theme and they didn't work, but hopefully it gives some intuition:

template<template<typename mycmp_t>
         int (*cmp)(const mydata_t &, const mycmp_t &)
         >
void insert(const mydata_t &value, const mycmp_t &key);

(gives me expected 'class' before '(' token, expected identifier before '(' token, expected '>' before '(' token). I also imagined using a template like template<int (*cmp)(const mydata_t &, const mycmp_t &), typename mycmp_t> but it says the mycmp_t present in the signature isn't defined (yet) and things like that.

leif
  • 1,987
  • 4
  • 19
  • 22
  • "*I am using C++11 with the gnu compiler (version 4.7), and C++0x with the intel compiler.*" I have absolutely _no_ idea what this means. – ildjarn Jul 14 '12 at 03:39
  • 1
    Yes, noting of course that c++0x and c++11 are the same thing. ;-] – ildjarn Jul 14 '12 at 03:44
  • They should be, but I am not yet convinced that what intel and gcc implement are really the same thing. :) – leif Jul 14 '12 at 03:46
  • Is there a reason the comparison function is not part of the structure template parameters ? It usually is for maps and sets for example. – Matthieu M. Jul 14 '12 at 12:53
  • There are cases where we may want different comparison functions for the same structure. Alternatively, take the case of iterating over the structure. You could easily want to use different callback functions on the same structure. – leif Jul 14 '12 at 20:10

1 Answers1

1

Normally, you pass callbacks another way in idiomatic C++: Not bound to a specific type or arguments and as a normal parameter:

template<class K, class F>
void insert(T const& v, K const& k, F f);

To answer your actual question though, no, you can't do that.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • I want the template instantiated for each comparison function, so I can make sure the calls get inlined. Not exactly going for idiomatic C++. – leif Jul 14 '12 at 03:41
  • @leif: Well, you're not making sure they're getting inlined by passing them as non-type template arguments. And the compiler can certainly inline them just as nicely when passed as a normal parameter if the `insert` function is inlined, and sometimes even if not. And if you're *really* concerned about performance, then you don't want function pointers but functors, which can *easily* get inlined. – Xeo Jul 14 '12 at 03:43
  • 2
    @leif: Easiest way to make any function a functor would be a lambda: `[](T const& v, K const& k){ return func(v, k); }`. This doesn't turn the function into a function pointer and doesn't inhibit inlining. – Xeo Jul 14 '12 at 03:46