Reputation: 6606
Is there a concise way to point to all instances of a templated function without using macros?
I have several templated functions that I want to test across a variety of types:
template<typename T>
void function1() {
return;
}
template<typename T>
void function2() {
return;
}
template<typename T>
void function3() {
return;
}
I can do this with a macro:
#define TEST_ACROSS_TYPES(fn) \
fn<int>(); \
fn<bool>(); \
fn<char>(); \
fn<double>(); \
TEST_ACROSS_TYPES(function1);
TEST_ACROSS_TYPES(function2);
But, (1) Macros are ugly and hard for others to follow, and (2) I'm using CATCH
, which doesn't play nice when using macros to set up test cases.
Is there a way to do something like this:
void testAcrossTypes(SomeType f) {
f<int> ();
f<bool> ();
f<char> ();
f<double> ();
}
which seems much cleaner, except for the problem of defining SomeType
. This question (How to define typedef of function pointer which has template arguments) explains how to define a pointer to a templated function; but, requires that the template arguments be specified.
For clarification: Imagine function1
, function2
, and function3
each test a different templated function. Each function needs to be tested for int
, byte
, char
, double
, etc. I want to avoid having to explicitly set up many (i.e. num_functions * num_types) tests for each function. Instead, I want to have a single method that points to the test function (function1
, function2
, etc.) and runs it for each template type, thus consolidating
function1<int>();
function1<byte>();
function1<char>();
function1<double();
...
function2<int>();
function2<byte>();
function2<char>();
function2<double();
...
function3<int>();
function3<byte>();
function3<char>();
function3<double();
...
into just one call per test function
testAcrossTypes(function1);
testAcrossTypes(function2);
testAcrossTypes(function3);
Upvotes: 2
Views: 280
Reputation: 50568
You can accomplish it by means of a type-erased functor, like the one in the following example:
#include<vector>
template<typename T>
void function1() { }
template<typename T>
void function2() { }
template<typename T>
void function3() { }
struct Test {
template<typename T>
static void proto() {
function1<T>();
function2<T>();
function3<T>();
}
void operator()() {
for(auto &f: vec) f();
}
template<typename... T>
static Test create() {
Test test;
int arr[] = { (test.vec.emplace_back(&proto<T>), 0)... };
(void)arr;
return test;
}
using func = void(*)(void);
std::vector<func> vec;
};
void testAcrossTypes(Test test) {
test();
}
int main() {
testAcrossTypes(Test::create<int, bool, char, double>());
}
It's easy to modify in both cases:
New functions require to be added to the proto
static member method and that's all
Adding a new type is a matter of using it when call create
, as shown in the above example
The functor will keep in charge of creating the N*M calls to be executed.
Moreover, you don't need to move your functions in a bunch of structs to be able to use them.
Upvotes: 3
Reputation: 206727
What you are trying to accomplish with
void testAcrossTypes(SomeType f) {
f<int> ();
f<bool> ();
f<char> ();
f<double> ();
}
would be possible if SomeType
could be a template template argument. However, the standard does not allow function templates as template template argument.
From the C++11 Standard:
14.3.3 Template template arguments
1 A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.
Your best option is to use functors instead of functions. Example:
template<typename T>
struct function1
{
void operator()() {
return;
}
};
template<typename T>
struct function2
{
void operator()() {
return;
}
};
template < template <typename> class F>
void testAcrossTypes() {
F<int>()();
F<bool>()();
F<char>()();
F<double>()();
}
int main()
{
testAcrossTypes<function1>();
testAcrossTypes<function2>();
}
Upvotes: 5