0

So I really need a class with the following structure, where the class is templated and arr is an array of function pointers, but I can't seem to figure out the proper syntax:

--myclass.h--

#include <vector>

template <typename T>
class MyClass {
    typedef void (*fptr)(std::vector<T> data);
    static void foo(std::vector<T> data);
    static void bar(std::vector<T> data);
    static void baz(std::vector<T> data);
    static const fptr arr[3];
};

--myclass.cpp--

#include "myclass.h"
#include <vector>

template <typename T> void MyClass<T>::foo(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::bar(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::baz(std::vector<T> data) { ... }

template <typename T> MyClass<T>::fptr MyClass<T>::arr[3] = { &foo, &bar, &baz };

If it helps, my ultimate goal is for a fourth member function to call either foo, bar, or baz from the array so I can avoid the overhead of multiple if-else statements (my actual implementation has closer to 50 of these functions). Is there a better way to do this?

Kody Puebla
  • 227
  • 2
  • 10
  • You have a lot of unrelated syntax errors (extra semi-colons, extra `static` keywords, incorrect typedef, conflicting names, ...). Fix those before asking your question. Better yet, provide a compilable example and ask about how to add what you want to it. – Nelfeal Dec 29 '18 at 08:27
  • You are aware of [templates and headers](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file), are you? And are you sure you really want to *copy* the vectors in all functions? – Aconcagua Dec 29 '18 at 08:33

3 Answers3

1

fptr is declared const, so define it const too. Also, because Sort is a template, you need typename to refer to MyClass<T>::fptr.

template<typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };

Side note: you won't be able to put this definition or the definitions of your static functions in a source file since they are templates.

Demo

Moreover, consider using using instead of typedef, and std::array instead of a raw array:

using fptr = void (*)(std::vector<T>);
static const std::array<fptr, 3> arr;
// [...]
template<typename T>
const std::array<typename MyClass<T>::fptr, 3> MyClass<T>::arr = { &foo, &bar, &baz };

Demo

Is there a better way to do this?

Probably, but I can't say without more details abour what you want to do exactly.

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
  • Sorry for all of the unrelated errors. Hopefully I fixed those in the edits to make things clearer. I just didn't want to copy-paste 700 lines of code. – Kody Puebla Dec 29 '18 at 08:38
  • What is the advantage of using `std::array` over a raw array? – Kody Puebla Dec 29 '18 at 08:47
  • @KodyPuebla Consistent interface with other standard containers... You get iterators, `std::array` passed as reference preserves its type (whereas arrays decay to pointers), so e. g. size remains usable, ... – Aconcagua Dec 29 '18 at 08:47
  • 1
    @KodyPuebla Its methods, the fact that it doesn't decay into a pointer, and taste. Without any overhead. – Nelfeal Dec 29 '18 at 08:50
0

Move the whole class template into the .hpp file and initialize arr with the same signature as it was declared:

template <typename T>
class MyClass {
    typedef void (*fptr)(std::vector<T> data);

    static void foo(std::vector<T> data) {}
    static void bar(std::vector<T> data) {}
    static void baz(std::vector<T> data) {}

    static const fptr arr[3];
};

template <typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };

You may also define arr directly:

#include <iostream>
#include <vector>
#include <array>

template <typename T>
class MyClass {
    typedef void (*fptr)(std::vector<T> data);

    static void foo(std::vector<T> data) {
        for(int i : data) std::cout << "foo " << i << "\n";
    }
    static void bar(std::vector<T> data) {
        for(int i : data) std::cout << "bar " << i << "\n";
    }
    static void baz(std::vector<T> data) {
        for(int i : data) std::cout << "baz " << i << "\n";
    }
public:
    static constexpr std::array<fptr,3> arr = { &foo, &bar, &baz };
};

int main() {
    MyClass<int> a;
    a.arr[0](std::vector<int>(1));
    a.arr[1](std::vector<int>(2));
    a.arr[2](std::vector<int>(3));
}

Output:

foo 0
bar 0
bar 0
baz 0
baz 0
baz 0
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
0

You can use std::function and store them into a vector. Here is what I have come up with so far.

#include <exception>
#include <iostream>
#include <functional>
#include <vector>

template<typename T>
class MyClass {
private:
    std::vector<std::function<void(std::vector<T>)>> myFuncs_;

public:
    MyClass() = default;

    void addFunc( std::function<void(std::vector<T>)> func ) {
        myFuncs_.push_back(func);
    }

    void caller(unsigned idx, std::vector<T> v ) {
        return myFuncs_.at(idx)( v );
    }

    static void foo(std::vector<T> data) {
        std::cout << "foo() called:\n";

        for (auto& d : data)
            std::cout << d << " ";
        std::cout << '\n';
    }

    static void bar(std::vector<T> data) {
        std::cout << "bar() called:\n";

        for (auto& d : data)
            std::cout << d << " ";
        std::cout << '\n';
    }
};

int main() {
    try {
        MyClass<int> myClass;
        std::vector<int> a{ 1,3,5,7,9 };
        std::vector<int> b{ 2,4,6,8,10 };

        std::function<void(std::vector<int>)> funcA = MyClass<int>::foo;
        std::function<void(std::vector<int>)> funcB = MyClass<int>::bar;
        myClass.addFunc( funcA );
        myClass.addFunc( funcB );

        myClass.caller(0, a);
        myClass.caller(1, b);       

    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}

-Output-

MyClass::foo() was called:
1 3 5 7 9
MyClass::bar() was called:
2 4 6 8 10

Not sure if this is exactly what you was looking for. In this example MyClass::caller(...) takes two parameters, the index into the vector for which function pointer you want, and the parameter or data that the function requires as input.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59