Passing templated-function by reference in recursive template - c++

In my PhD, I very often use matrices of various dimensions and data types. For first time, I use recursive templates in C++11 for manipulating my non-contiguous arrays, so it is the last time I see calloc and free. With the help of stackoverflow link1 and link2 I achieved my initial goal of de&allocating them. Greedy me, I now want my class to perform the basic cellwise operations e.i. addition, division. It works fine if I use enum to determine which operation is performed, but I fail to use reference to an other templated function that performs the operation.
The main:
//Define the size of each dimension in a vector
int height = 3, width = 2;
std::vector<int> dimensions;
dimensions.push_back(height);
dimensions.push_back(width);
// Allocate a table of doubles 3x2
smatrix<double **> dbltbl(dimensions);
// Assign values in the cells
for (int r = 0; r < height; ++r)
for (int c = 0; c < width; ++c) {
dbltbl.uacc()[r][c] = (r * width + c) * 2.6;
}
// Create a table of ints from the table of doubles (rounded copy)
smatrix<int **> inttbl = dbltbl;
// Add cell-wise the table of ints to the table of doubles
dbltbl.cellwise_add(inttbl);
The enum way
The enum:
enum clc_op { addition, subtration, multiplication, division };
The operation function:
template <typename S, typename T>
T add(S one, T two) {
return one + two;
}
The recursive template solution:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, enum clc_op operation) {
switch (operation) {
case clc_op::addition:
dest = add(src, dest);
break;
//…
//...
}
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, enum clc_op operation) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation)
}
}
The class method (e.g. P = double** and U=int**):
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, clc_op::addition);
}
The output:
==========================================
Table of doubles:
0 2.6
5.2 7.8
10.4 13
==========================================
Table of ints from the table of doubles:
0 2
5 7
10 13
==========================================
Table of doubles+ints:
0 4.6
10.2 14.8
20.4 26
This solution doesn’t look elegant, making me believe it is the wrong approach. So, I try to pass the operation as reference to function, and I fail hard time.
The function by reference way:
The addition (operation) function remains the same. The recursive solution:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, T (*operation)(S, T)) {
dest = operation(src, dest);
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, T (*operation)(S, T)) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
The class method:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, add<U, P>);
}
The error:
./sm_example/smatrix.hpp:305:17: required from ‘void smatrix<P>::cellwise_add(const smatrix<U>&) [with U = int**; P = double**]’
./sm_example/sm_example.cpp:157:35: required from here
./sm_example/smatrix.hpp:159:19: error: invalid operands of types ‘double**’ and ‘double**’ to binary ‘operator+’
return (T)one + two;
I understand that addition between pointers is not allowed, although I know it will not happen the compiler doesn't. I have no clue how I could work around it. How do I pass the operation’s template-function (add) by reference in the recursive template-function? Do I use templates in a wrong way?
I do not want to use std::vector for the time being, but comments are welcome. Worst case scenario, my dataset reaches 100MBytes in 5 dimensions.
Solution in C++11 thx to #Yakk below
The operation function:
struct add {
template <typename S, typename T>
S operator()(S &x, T &y) { return x + y; }
};
The rock bottom of recursive template solution:
template <typename S, typename T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op &&operation) {
dest = operation(dest, src);
return;
}
The class method:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
cellwise_ops(addend.uacc(), _full, _dim, add());
}
If you made it so far, thank you!
Chris

Don't use function pointers.
template <typename S, typename T>
T add(S one, T two) {
return (T)one + two;
}
const auto do_add=[](auto&&...args)->decltype(auto) {
return add( decltype(args)(args)... );
};
or
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define DO_FUNC(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
const auto do_add=DO_FUNC(add);
in both of these cases, we have a single object do_add that represents adding things. This can also be written manually as a struct with an operator() if you care.
do_add isn't a function pointer.
template <class S, class T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op&& operation)
{
dest = operation(src, dest);
}
template <class S, class T, class Op>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, Op&& operation)
{
if (dims.size() == 0)
return false;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
and we are done.

Related

Can I allocate a series of variables on the stack based on template arguments?

In a piece of code I'm writing, I receive packets as uint8_t * and std::size_t combination. I can register functions to call with these two parameters, based on which file descriptor the packet was received from. I use an std::map<int, std::function<void(const uint8_t *, std::size_t)> > handlers to keep track of which function to call.
I would like to be able to (indirectly) register functions with arbitrary arguments. I already have a function like this to transform from the uint8_t * and std::size_t to separate variables:
int unpack(const uint8_t *buf, std::size_t len) { return 0; }
template <typename T, typename... Types>
int unpack(const uint8_t *buf, std::size_t len, T &var1, Types... var2) {
static_assert(std::is_trivially_copyable<T>::value, "unpack() only works for primitive types");
if (len < sizeof(T)) return -1;
var1 = *reinterpret_cast<const T *>(buf);
const auto sum = unpack(buf + sizeof(T), len - sizeof(T), var2...);
const auto ret = (sum == -1) ? -1 : sum + sizeof(T);
return ret;
}
My question is: Is it possible with C++20 to auto-generate a function that convers from uint8_t * and std::size_t to the arguments that a passed function needs?
I would like to be able to do this:
void handler(unsigned int i) { ... }
int main(int argc, char ** argv) {
/* some code generating an fd */
handlers[fd] = function_returning_an_unpacker_function_that_calls_handler(handler);
edit: I realize I went a bit too short on my answer, as some mentioned (thanks!).
I am wondering if it is possible (and if so, how?) to implement the function_returning_an_unpacker_function_that_calls_handler function. I started out doing something like this (written from memory):
template<typename... Types>
std::function<void(const uint8_t * buf, std::size_t)>
function_returning_an_unpacker_function_that_calls_handler(std::function<void(Types...)> function_to_call) {
const auto ret = new auto([fun](const uint8_t * buf, std::size_t len) -> void {
const auto unpack_result = unpack(buf, len, list_of_variables_based_on_template_params);
if(unpack_result == -1) return nullptr;
function_to_call(list_of_variables_based_on_template_params);
};
return ret;
}
This is also why I supplied the unpack function. The problem I'm encountering is that I'm struggling with the list_of_variables_based_on_template_params bit. I haven't found any way to generate a list of variables that I can repeat identically in two places.
I also looked a little bit into using std::tuple::tie and friends, but I didn't see a solution there either.
It's possible, just annoying to write.
First you need a trait to get parameters from a function type:
template <typename T>
struct FuncTraits {};
#define GEN_FUNC_TRAITS_A(c, v, ref, noex) \
template <typename R, typename ...P> \
struct FuncTraits<R(P...) c v ref noex> \
{ \
template <template <typename...> typename T> \
using ApplyParams = T<P...>; \
};
#define GEN_FUNC_TRAITS_B(c, v, ref) \
GEN_FUNC_TRAITS_A(c, v, ref,) \
GEN_FUNC_TRAITS_A(c, v, ref, noexcept)
#define GEN_FUNC_TRAITS_C(c, v) \
GEN_FUNC_TRAITS_B(c, v,) \
GEN_FUNC_TRAITS_B(c, v, &) \
GEN_FUNC_TRAITS_B(c, v, &&)
#define GEN_FUNC_TRAITS(c) \
GEN_FUNC_TRAITS_C(c,) \
GEN_FUNC_TRAITS_C(c, volatile)
GEN_FUNC_TRAITS()
GEN_FUNC_TRAITS(const)
Then some templates to analyze what kind of callable (function, function pointer, or a functor) you got, and apply the trait accordingly:
template <typename T> struct RemoveMemPtr {using type = T;};
template <typename T, typename C> struct RemoveMemPtr<T C::*> {using type = T;};
template <typename T>
struct ToFuncType {};
template <typename T>
requires std::is_function_v<std::remove_pointer_t<T>>
struct ToFuncType<T> {using type = std::remove_pointer_t<T>;};
template <typename T>
requires requires {&T::operator();}
struct ToFuncType<T>
{
using type = typename RemoveMemPtr<decltype(&T::operator())>::type;
};
Then you can make a templated functor that automatically unwraps the arguments. Since Unwrap() must be called in order, and function arguments are evaluated in unspecified order, we need a tuple (or something similar) that accepts a braced list:
template <typename T>
T Unpack(char *&, std::size_t &)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
return {};
}
template <typename F>
struct WrapFunctor
{
template <typename ...P>
struct Impl
{
std::decay_t<F> func;
void operator()(char *p, std::size_t n)
{
std::apply(func, std::tuple{Unpack<P>(p, n)...});
}
};
};
template <typename F>
auto Wrap(F &&func)
{
using Functor = typename FuncTraits<typename ToFuncType<std::remove_cvref_t<F>>::type>::template ApplyParams<WrapFunctor<F>::template Impl>;
return Functor{std::forward<F>(func)};
}
Finally, some tests:
void foo(int, float, char)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main()
{
Wrap(foo)(nullptr, 42);
Wrap(&foo)(nullptr, 42);
Wrap([](int, float, char){std::cout << __PRETTY_FUNCTION__ << '\n';})(nullptr, 42);
}
I've changed the signature of Unpack() to take the parameters by reference and unpack one variable at a time.
Almost forgot: var1 = *reinterpret_cast<const T *>(buf); is a strict aliasing violation and UB. Prefer memcpy.
This answer is very similar to the first one, but it leverages the use of CTAD and std::function to figure out the function signature.
Creates a tuple based on the function signature, and passes both the argument types and the elements from the tuple on to unpack.
#include <iostream>
#include <tuple>
#include <type_traits>
#include <cstring>
#include <functional>
int unpack(const uint8_t *buf, std::size_t len) { return 0; }
template <typename T, typename... Types>
int unpack(const uint8_t *buf, std::size_t len, T &var1, Types&... var2) {
static_assert(std::is_trivially_copyable<T>::value, "unpack() only works for primitive types");
if (len < sizeof(T)) return -1;
var1 = *reinterpret_cast<const T *>(buf);
std::cout << "In unpack " << var1 << "\n";
const auto sum = unpack(buf + sizeof(T), len - sizeof(T), var2...);
const auto ret = (sum == -1) ? -1 : sum + sizeof(T);
return ret;
}
template<typename T, typename R, typename... Args>
std::function<void(const uint8_t * buf, std::size_t)>
unpack_wrapper_impl(T function_to_call, std::function<R(Args...)>) {
return [function_to_call](const uint8_t *buf, std::size_t len) -> void {
std::tuple<std::decay_t<Args>...> tup;
std::apply([&](auto&... args) {
unpack(buf, len, args...);
}, tup);
std::apply(function_to_call, tup);
};
}
template<typename T>
std::function<void(const uint8_t * buf, std::size_t)>
unpack_wrapper(T&& function_to_call) {
return unpack_wrapper_impl(std::forward<T>(function_to_call), std::function{function_to_call});
}
void test(int a, int b) {
std::cout << a << " " << b << "\n";
}
int main() {
int a= 5, b = 9;
uint8_t* buf = new uint8_t[8];
std::memcpy(buf, &a, 4);
std::memcpy(buf + 4, &b, 4);
auto f = unpack_wrapper(test);
f(buf, 8);
}

How to partially specialize a template based on the relation between its two integer parameters

I want to design a m x n matrix class (as a template parameterized by m rows and n columns) and need to specialize it in order to equip it with operations that are mathematically possible based on three conditions:
m > n
m == n
no specialization for m < n, that is, basic or default implementation
The template signature is simply:
template <size_t m, size_t n, typename T = double> class MatrixBase
{
....
};
How do I do that? Can it be done with type traits? Or should I use std::conditional<> or std::enable_if<> ?. Conceptually, what I want to accomplish is to add methods to a class but without subclassing it and creating any inheritance hierarchy. The derivation tree I want to use for other things, namely the data storage within the matrix.
So I would like to have a matrix that if declared as for instance MatrixBase<4, 4, float> has (by virtue of specialization) a method called inverse (), while matrices declared with m <> n don't. Similarly, extra methods for matrices with m > n.
It can be done with std::enable_if:
template <size_t m, size_t n, typename T = double>
class MatrixBase
{
public:
template <typename T1 = T>
std::enable_if_t<m == n, MatrixBase<m, m, T1>> inverse() const
{
// Calculate inverse
return{};
}
};
int main(int argc, const char *argv[])
{
auto msquare = MatrixBase<4, 4>();
auto mrect = MatrixBase<4, 3>();
msquare.inverse(); // No error
mrect.inverse(); // Compilation error
return 0;
}
For partial specialization you can also use enable_if:
template <size_t m, size_t n, typename T = double, typename E = void>
class MatrixBase
{
public:
template <typename T1 = T>
std::enable_if_t<m == n, MatrixBase<m, m, T1>> inverse() const
{
// Calculate inverse
return{};
}
};
template <size_t m, size_t n, typename T>
class MatrixBase<m, n, T, std::enable_if_t<m == n, void>>
{
public:
static bool m_equals_n()
{
return true;
}
};
template <size_t m, size_t n, typename T>
class MatrixBase<m, n, T, std::enable_if_t<n < m, void>>
{
public:
static bool m_greater_than_n()
{
return true;
}
};
template <size_t m, size_t n, typename T>
class MatrixBase < m, n, T, std::enable_if_t<m < n, void>>
{
public:
static bool m_less_than_n()
{
return true;
}
};
int main(int argc, const char *argv[])
{
auto msquare = MatrixBase<4, 4>();
auto m_4_3 = MatrixBase<4, 3>();
auto m_3_4 = MatrixBase<3, 4>();
msquare.m_equals_n();
//msquare.m_greater_than_n(); // Compilation error
m_4_3.m_greater_than_n();
m_3_4.m_less_than_n();
return 0;
}

How to conditionally add a function to a class template?

I have a Matrix class template as follows:
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
What I want is to define a .setIdentity() function only for instantiations when nrows==ncols is true at compile time. And there will be no definition of .setIdentity() when nrows==ncols is false.
What I am trying is using enable_if idiom, but that will define the function for all cases. Isn't it?
You can do it with std::enable_if in the following mode
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{ /* do something */ }
A full example
#include <type_traits>
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{ return data[i][j]; }
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{ /* do something */ }
};
int main()
{
Matrix<int, 3, 3> mi3;
Matrix<int, 3, 2> mnoi;
mi3.setIdentity();
// mnoi.setIdentity(); error
return 0;
}
--- EDIT ---
As pointed in a comment by Niall (regarding the TemplateRex's answer, but my solution suffer from the same defect) this solution can be circonvented expliciting the number of rows and columns in this way
mi3.setIdentity<4, 4>();
(but this isn't a real problem (IMHO) because mi3 is a square matrix and setIdentity() could work with real dimensions (nrows and ncols)) or even with
mnoi.setIdentity<4, 4>()
(and this is a big problem (IMHO) because mnoi isn't a square matrix).
Obviously there is the solution proposed by Niall (add a static_assert; something like
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{
static_assert(r == nrows && c == ncols, "no square matrix");
/* do something else */
}
or something similar) but I propose to add the same check in std::enable_if.
I mean
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if< (r == c)
&& (r == nrows)
&& (c == ncols)>::type setIdentity ()
{ /* do something */ }
The lazy and needlessly repetitive way
Just add a partial specialization:
template<typename T, std::size_t N>
class Matrix<T, N, N>
{
T data[N][N];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
void setidentity(/*whatever params*/) { std::cout << "yay!"; }
};
Live Example
For general N * M matrices, the general template will be instantiated, whereas only for N * N matrics, this specialization is a better match.
Disadvantage: code repetition of all regular code. Could use a base class, but it's actually easier to do some SFINAE magic (below)
A slightly harder but more economical way
You can also use SFINAE by adding hidden template parameters N and M that default to nrows and ncols to setidentity, and to enable_if on the condition N == M.
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
template <std::size_t N = nrows, std::size_t M = ncols, std::enable_if_t<(N == M)>* = nullptr>
void setidentity(/*whatever params*/) {
static_assert(N == nrows && M == ncols, "invalid");
std::cout << "yay!";
}
};
Or, since the question was tagged C++11, use typename std::enable_if<(N == M)>::type instead.
Live Example
Use a pseudo-CRTP to add modular support for something.
template<class T, std::size_t nrows, std::size_t ncols>
class Matrix;
template<class T, std::size_t size>
struct MatrixDiagonalSupport {
auto self() { return static_cast<Matrix<T, size, size>*>(this); }
auto self() const { return static_cast<Matrix<T, size, size> const*>(this); }
void setIdentity() {
for (std::size_t i = 0; i < size; ++i) {
for (std::size_t j = 0; j < i; ++j) {
(*self())(i,j) = {};
}
(*self())(i,i) = 1; // hope T supports this!
for (std::size_t j = i+1; j < size; ++j) {
(*self())(i,j) = {};
}
}
}
};
template<class T>
struct empty_t {};
template<bool b, class T>
using maybe= std::conditional_t<b, T, empty_t<T>>;
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix: public maybe<nrows==ncols,MatrixDiagonalSupport<T, nrows>>
{
// ...
Here we inherit from nothing if we aren't diagonal, and a class implementing set identity if we are diagonal.
Users of Matrix get .setIdentity() from its parent magically if it is right.
static_cast inside self() ends up being a zero-cost abstraction and giving the base class access to the child class.
This is pseudo-CRTP because we don't actually pass the derived class type to the parent, just enough information for the parent to reconstruct it.
This solution makes the method an actual method, and avoids any kind of SFINAE trickery.
Live example
In C++11 replace conditional_t<?> with typename conditional<?>::type:
template<bool b, class T>
using maybe=typename std::conditional<b, T, empty_t<T>>::type;
and everything should compile.
A basic, but simple solution not mentioned by any other answer: you can use std::conditional and inheritance.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
struct HasSetIdentity {
void setIdentity() { }
};
struct HasNotSetIdentity {};
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix: public std::conditional<(nrows==ncols), HasSetIdentity, HasNotSetIdentity>::type
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
int main() {
Matrix<int, 2,2> m1;
m1.setIdentity();
Matrix<int, 2,3> m2;
// Method not available
// m2.setIdentity();
}
You can still move data down the hierarchy if you need them to be shared by all the subobjects.
It mostly depends on the real problem.
skypjack and max66 have both presented simple answers to the problem. This is just an alternate way of doing it, using simple inheritance, although it means the use of a child class for square matrices:
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
protected:
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
template<typename T, std::size_t N>
class SqMatrix : public Matrix <T, N, N>
{
public:
setIdentity()
{
//Do whatever
}
}

Avoiding code duplication for runtime-to-compile-time numeric parameter translation

Suppose we have function such as
template <typename T, unsigned N> void foo();
and for simplicity assume that we know that only (constant) values N_1, N_2 ... N_k are valid for N.
Now, suppose I want to make that compile-time parameter a run-time one, using foo() as a black-box, i.e. implement:
template <typename T> void foo(unsigned n);
by making foo<,>() calls. How should I go about doing that? Obviously, I can write:
template <typename T> void foo(unsigned n) {
switch(n) {
case N_1 : foo<T, N_1>(); break;
case N_2 : foo<T, N_2>(); break;
// etc. etc.
case N_k : foo<T, N_k>(); break;
}
}
... but this makes me feel all dirty. I could use a MAP() meta-macro to generate these k lines, I suppose; but can I do anything better and less-macroish to achieve the same? Is it possible to write something like the above that's general, and works for every variadic template and a fixed sequence of constant values?
Notes:
C++11/14/17-specific suggestions are obviously welcome.
The N's are not necessarily contiguous, nor small, nor sorted. e.g. suppose N_2 = 123456789 and N_5 = 1.
You could make a function pointer table:
using F = void(*)();
template <class T, class >
struct Table;
template <class T, size_t... Is>
struct Table<T, std::index_sequence<Is...> > {
static constexpr F fns[] = {
foo<T, Is>...
};
};
template <class T, size_t... Is>
constexpr F Table<T, std::index_sequence<Is...> >::fns[sizeof...(Is)];
And then just invoke the one you want:
template <class T, size_t N>
struct MakeTable : Table<T, std::make_index_sequence<N>> { };
template <typename T>
void foo(unsigned n) {
MakeTable<T, MaxN>::fns[n]();
}
If the N_ks aren't contiguous, then we can use a lambda for inline parameter unpacking:
template <class T>
void foo(unsigned n) {
using seq = std::index_sequence<N_1, N_2, ..., N_k>;
indexer(seq)([n](auto i){
if (n == i) {
f<T, i>();
}
});
}
If the above is too slow, then I guess just manually build a std::unordered_map<unsigned, void(*)()> or something.
In these kind of situations I like to build a static table of function pointers, with a dynamic parameter deciding which one to dispatch to. Below is an implementation that achieves this, in the function foo_dynamic. To this function, you specify the maximum value of N you'd like to support, and it builds a static table of function pointers using some recursive templates. You then dereference into this table with your dynamic parameter.
using ftype = void (*)();
template <typename T, unsigned N> void foo()
{
std::cout << N << std::endl;
}
template <typename T, unsigned max>
struct TablePopulator
{
static void populateFTable(ftype* table)
{
table[max] = foo<T,max>;
TablePopulator<T,max-1>::populateFTable(table);
}
};
template <typename T>
struct TablePopulator<T, 0>
{
static void populateFTable(ftype* table)
{
table[0] = foo<T,0>;
}
};
template<typename T, unsigned max_N>
std::array<ftype, max_N>& initTable()
{
static std::array<ftype, max_N> table;
TablePopulator<T, max_N-1>::populateFTable(table.data());
return table;
}
template<typename T, unsigned max_N>
void foo_dynamic(unsigned actualN)
{
static auto ftable = initTable<T, max_N>();
if(actualN >= max_N)
throw std::runtime_error("Max param exceeded");
ftable[actualN]();
}
int main()
{
foo_dynamic<int, 10>(1);
foo_dynamic<int, 10>(5);
return 0;
}
EDIT: Given the constraints in the question edit, here's an approach where valid indices are specified manually, which uses an unordered_map instead of an array:
using ftype = void (*)();
template <typename T, unsigned N> void foo()
{
std::cout << N << std::endl;
}
template<typename T, size_t ... Indices>
void foo_dynamic_indices(size_t actual_index)
{
static std::unordered_map<size_t, ftype> fmap = {{Indices, foo<T,Indices>}...};
auto fIt = fmap.find(actual_index);
if(fIt == fmap.end())
throw std::runtime_error("Index not found");
fIt->second();
}
int main()
{
foo_dynamic_indices<int, 0, 3, 400, 1021, 10000000>(10000000);
foo_dynamic_indices<int, 0, 3, 400, 1021, 10000000>(4); //Exception
return 0;
}

check if member exists using enable_if

Here's what I'm trying to do:
template <typename T> struct Model
{
vector<T> vertices ;
#if T has a .normal member
void transform( Matrix m )
{
each vertex in vertices
{
vertex.pos = m * vertex.pos ;
vertex.normal = m * vertex.normal ;
}
}
#endif
#if T has NO .normal member
void transform( Matrix m )
{
each vertex in vertices
{
vertex.pos = m * vertex.pos ;
}
}
#endif
} ;
I've seen examples of using enable_if, but I cannot understand how to apply enable_if to this problem, or if it even can be applied.
This has become way easier with C++11.
template <typename T> struct Model
{
vector<T> vertices;
void transform( Matrix m )
{
for(auto &&vertex : vertices)
{
vertex.pos = m * vertex.pos;
modifyNormal(vertex, m, special_());
}
}
private:
struct general_ {};
struct special_ : general_ {};
template<typename> struct int_ { typedef int type; };
template<typename Lhs, typename Rhs,
typename int_<decltype(Lhs::normal)>::type = 0>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, special_) {
lhs.normal = rhs * lhs.normal;
}
template<typename Lhs, typename Rhs>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, general_) {
// do nothing
}
};
Things to note:
You can name non-static data members in decltype and sizeof without needing an object.
You can apply extended SFINAE. Basically any expression can be checked and if it is not valid when the arguments are substituted, the template is ignored.
I know this question already has some answers but I think my solution to this problem is a bit different and could help someone.
The following example checks whether passed type contains c_str() function member:
template <typename, typename = void>
struct has_c_str : false_type {};
template <typename T>
struct has_c_str<T, void_t<decltype(&T::c_str)>> : std::is_same<char const*, decltype(declval<T>().c_str())>
{};
template <typename StringType,
typename std::enable_if<has_c_str<StringType>::value, StringType>::type* = nullptr>
bool setByString(StringType const& value) {
// use value.c_str()
}
In case there is a need to perform checks whether passed type contains specific data member, following can be used:
template <typename, typename = void>
struct has_field : std::false_type {};
template <typename T>
struct has_field<T, std::void_t<decltype(T::field)>> : std::is_convertible<decltype(T::field), long>
{};
template <typename T,
typename std::enable_if<has_field<T>::value, T>::type* = nullptr>
void fun(T const& value) {
// use value.field ...
}
UPDATE C++20
C++20 introduced constraints and concepts, core language features in this C++ version.
If we want to check whether template parameter contains c_str member function, then, the following will do the work:
template<typename T>
concept HasCStr = requires(T t) { t.c_str(); };
template <HasCStr StringType>
void setByString(StringType const& value) {
// use value.c_str()
}
Furthermore, if we want to check if the data member, which is convertible to long, exists, following can be used:
template<typename T>
concept HasField = requires(T t) {
{ t.field } -> std::convertible_to<long>;
};
template <HasField T>
void fun(T const& value) {
// use value.field
}
By using C++20, we get much shorter and much more readable code that clearly expresses it's functionality.
You need a meta function to detect your member so that you can use enable_if. The idiom to do this is called Member Detector. It's a bit tricky, but it can be done!
This isn't an answer to your exact case, but it is an alternative answer to the question title and problem in general.
#include <iostream>
#include <vector>
struct Foo {
size_t length() { return 5; }
};
struct Bar {
void length();
};
template <typename R, bool result = std::is_same<decltype(((R*)nullptr)->length()), size_t>::value>
constexpr bool hasLengthHelper(int) {
return result;
}
template <typename R>
constexpr bool hasLengthHelper(...) { return false; }
template <typename R>
constexpr bool hasLength() {
return hasLengthHelper<R>(0);
}
// function is only valid if `.length()` is present, with return type `size_t`
template <typename R>
typename std::enable_if<hasLength<R>(), size_t>::type lengthOf (R r) {
return r.length();
}
int main() {
std::cout <<
hasLength<Foo>() << "; " <<
hasLength<std::vector<int>>() << "; " <<
hasLength<Bar>() << ";" <<
lengthOf(Foo()) <<
std::endl;
// 1; 0; 0; 5
return 0;
}
Relevant https://ideone.com/utZqjk.
Credits to dyreshark on the freenode IRC #c++.
template<
typename HTYPE,
typename = std::enable_if_t<std::is_same<decltype(HTYPE::var1), decltype(HTYPE::var1)>::value>
>
static void close_release
(HTYPE* ptr) {
ptr->var1;
}
Using enable_if and decltype to let compiler to check variable, hope to help.
While C++20's requires keyword has been mentioned, the code that's provided is still too complex for your needs, requiring the creation of a separate function for each case. Here's much simpler code for your use case, where a single function implementation suffices:
template <typename T> struct Model
{
vector<T> vertices ;
void transform( Matrix m )
{
each vertex in vertices
{
vertex.pos = m * vertex.pos ;
if constexpr (requires { &vertex.normal; })
vertex.normal = m * vertex.normal ;
}
}
} ;
Notes:
All the trick is on the if constexpr line. I've left your pseudo code as is, but removed the redundancy and added the if constexpr line.
The requires expression I've added simply attempts to access the address of the normal member, and evaluates to false if the expression is invalid. You could really use any expression that will succeed if normal is defined and fail if it's not.
For classes that do have normal, make sure the member is accessible from this code (e.g. it's either public or an appropriate friendship is specified). Otherwise the code would ignore the normal member as if it didn't exist at all.
See the "Simple requirements" section at https://en.cppreference.com/w/cpp/language/constraints for more information.
I know that it's little late, however...
typedef int Matrix;
struct NormalVertex {
int pos;
int normal;
};
struct Vertex {
int pos;
};
template <typename T> struct Model
{
typedef int No;
typedef char Yes;
template<typename U> static decltype (declval<U>().normal, Yes()) has_normal(U a);
static No has_normal(...);
vector<T> vertices ;
template <typename U = T>
typename enable_if<sizeof(has_normal(declval<U>())) == sizeof(Yes), void>::type
transform( Matrix m )
{
std::cout << "has .normal" << std::endl;
for (auto vertex : vertices)
{
vertex.pos = m * vertex.pos ;
vertex.normal = m * vertex.normal ;
}
}
template <typename U = T>
typename enable_if<sizeof(has_normal(declval<U>())) == sizeof(No), void>::type
transform( Matrix m )
{
std::cout << "has no .normal" << std::endl;
for (auto vertex : vertices)
{
vertex.pos = m * vertex.pos ;
}
}
} ;
int main()
{
Matrix matrix;
Model <NormalVertex> normal_model;
Vertex simple_vertex;
Model <Vertex> simple_model;
simple_model.transform(matrix);
normal_model.transform(matrix);
return 0;
}
I had a similar issue and my solution was to use boost's BOOST_TTI_HAS_MEMBER_DATA macro.
#include <boost/tti/has_member_data.hpp>
BOOST_TTI_HAS_MEMBER_DATA(normal)
template <typename T> struct Model
{
vector<T> vertices;
static constexpr bool hasNormal = has_member_data_normal<T, double>::value;
template<bool B = hasNormal, std::enable_if_t<B, int> = 0>
void transform( Matrix m )
{
for(auto&& vertex : vertices)
{
vertex.pos = m * vertex.pos ;
vertex.normal = m * vertex.normal ;
}
}
template<bool B = hasNormal, std::enable_if_t<!B, int> = 0>
void transform( Matrix m )
{
for(auto&& vertex : vertices)
{
vertex.pos = m * vertex.pos ;
}
}
};
If you don't want to be dependent on boost, then you can use #ltjax's answer to create your own has_member_data_normal struct.