Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass function with optional template type param to a class constructor and assign it to a method

Tags:

c++

I have two files: main.cpp and crypto.h containing the template class Crypto. In the class constructor I need to pass a function pointer and assign it to the (*keyGen) method. The function I need to pass has an optional param

template <class keyType>
class Crypto {
    private:
        keyType (*keyGen)(keyType);

    public:
        Crypto(keyType (*keyGen)(keyType)) {
            this->keyGen = keyGen;
        }

        void decode() {
            keyType foundKey;

            vector<string> output;
            keyType curKey = keyGen(); // Here keyGen has no args

            // if curKey does not decode the input
                curKey = keyGen(curKey); // Here keyGen has 1 arg of type keyType
            // else foundKey = curKey;

            // Save the decoded file
        }
};

In main.cpp

int keyGen(int key = -1) { // This is the optional param
    key++;
    return key;
}

int main() {
    // ...
    Crypto<int> crypto(keyGen);
    crypto.decode();
}

I need the decode method to be able to call keyGen with both no params or a keyType param. If keyGen is called with no params I need to return 0, else I need to return key+1. I thought about overloading the keyGen function, but since it is a function pointer it is not possible. I did a lot of research but I didn't find a solution.

like image 725
Damiano Scevola Avatar asked Feb 02 '18 10:02

Damiano Scevola


People also ask

How do you declare a template function in C++?

Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.

What can the template parameter in C++ template definition be?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is a non-type template parameter?

A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type. A pointer or reference to a class object.

How do you declare a template?

To instantiate a template class explicitly, follow the template keyword by a declaration (not definition) for the class, with the class identifier followed by the template arguments. template class Array<char>; template class String<19>; When you explicitly instantiate a class, all of its members are also instantiated.


1 Answers

If you want to have both keyGen() and keyGen(curKey) available, keyGen must be itself a function with default param. Note, that default value in signature does not change that signature - so pointer to int keyGen(int key = -1) must be of type int(*)(int).

You could add two member function of the same name, that internally call the function pointed to by keyGen with proper args:

template <class keyType>
class Crypto {
    ...
    void decode() {
        keyType foundKey;

        vector<string> output;
        keyType curKey = keyGenInternal(); // Here keyGen has no args

        // if curKey does not decode the input
        curKey = keyGenInternal(curKey); // Here keyGen has 1 arg of type keyType
        // else foundKey = curKey;
        // Save the decoded file
    }

private:
    keyType keyGenInternal() {
        return keyGen(-1);
    }

    keyType keyGenInternal(keyType key) {
        return keyGen(key);
    }

};

But for this to be a proper solution, you need to know the default value for the key - you can't simply put there -1, because for different key types this value may also be different. But you can make this value an additional template parameter:

template <class keyType, keyType defaultKey>
class Crypto {
    private:
        keyType keyGenInternal() {
            return keyGen(defaultKey);
        }

        keyType keyGenInternal(keyType key) {
            return keyGen(key);
        }
};

int main() {
    // ...
    Crypto<int, -1> crypto(keyGen);
    crypto.decode();
}

or pass it to constructor and store as a member:

template <class keyType>
class Crypto {
    private:
        keyType defaultKey;

    public:
        Crypto(keyType (*keyGen)(keyType), keyType default) : defaultKey(default) {
        this->keyGen = keyGen;
    }
};

int main() {
    // ...
    Crypto<int> crypto(keyGen, -1);
    crypto.decode();
}

I think it is the most straightforward solution.

like image 125
Mateusz Grzejek Avatar answered Oct 26 '22 23:10

Mateusz Grzejek