i wrote a template class that should work for double and std::complex. as it is suppose to be, all my methods are in the .hpp file. all but one. i had to specialize a method because at some place i have to compute the square of a double or the norm of a std::complex. more explicitly for the "double specialization" (A):
double a(2.0);
double b(0.0);
b = a*a;
for the "complex specialization" (B):
std::complex<double> a(2.0,3.0);
double b(0.0);
b = std::norm(a);
my questions are :
is there a way to avoid theses specializations by using a function that works for both double and complex ? (because the std::norm works only for complex...)
or the only solution is to cast the double a of the specialization (A) into a complex and then use only the specialization (B) as a general template (working for both double and complex)?
You can minimise the divergent case by introducing your own function as a square/norm wrapper:
template <typename T>
double square_or_norm(T x);
template<>
inline double square_or_norm(double x) { return x * x; }
template <>
inline double square_or_norm(std::complex<double> x) { return norm(x); }
Then, use it inside the function which needs it:
template <typename T>
T computation(T x) {
return some_code_with(x, square_or_norm(x));
}
You could define two function template overloads (when it comes to function templates, overloading is usually preferable to specialization) called compute_norm(), one accepting std::complex and one accepting unconstrained types. The unconstrained template would invoke operator *, while the constrained template would invoke std::norm().
#include <complex>
template<typename T>
double compute_norm(T t)
{ return t * t; }
template<typename T>
double compute_norm(std::complex<T> const& t)
{ return std::norm(t); }
Then, your generic code that can work both with a double and with a complex<double> would call compute_norm():
#include <iostream>
template<typename T>
void foo(T&& t)
{
// ...
double n = compute_norm(std::forward<T>(t));
std::cout << n << std::endl;
// ...
}
For instance, the following program:
int main()
{
double a(2.0);
foo(a);
std::complex<double> c(2.0, 3.0);
foo(c);
}
Will output:
4
13
Here is a live example.
If you have a conforming standard library, there is an overload of std::norm for floating point types:
26.4.9 Additional overloads [cmplx.over]
The following function templates shall have additional overloads:
arg norm
conj proj
imag real
The additional overloads shall be sufficient to ensure:
If the argument has type long double, then it is effectively cast to complex.
Otherwise, if the argument has type double or an integer type, then it is effectively cast to complex<
double>.
Otherwise, if the argument has type float, then it is effectively cast to complex.
This should work (and does on gcc 4.7.2)
#include <complex>
#include <iostream>
int main()
{
std::complex<double> c {1.5, -2.0};
double d = 2.5;
std::cout << "|c| = " << std::norm(c) << '\n'
<< "|d| = " << std::norm(d) << '\n';
}
Why not just use function overloading?
double myNorm(double);
double myNorm(std::complex<double>);
double myNorm(double x) {
return x * x;
}
double myNorm(std::complex<double> x) {
return std::norm(x);
}
You can put the implementation in your .cpp or (when inlined) in your header file.
Related
I want to write a template function that will work on both double and float, something like that:
template <typename T>
constexpr auto someCalc(const T x) {
return x * 4.0 + 3.0;
}
My issue is that both 4.0 and 3.0 are doubles literal, thus I get the following error on clang:
error: implicit conversion increases floating-point precision: 'const float' to 'double' [-Werror,-Wdouble-promotion]
Is there an elegant way to write this code without having the up-conversion to double? The best I can come up with, is this
template <typename T>
constexpr auto someCalc(const T x) {
constexpr T four = 4.0;
constexpr T three = 3.0;
return x * four + three;
}
which I find less readable and harder to maintain for larger/more complicated function.
I would do it this way:
template <typename T>
constexpr auto someCalc(const T x) {
return x * T(4.0) + T(3.0);
}
Or with static_cast, if you prefer it.
While HolyBlackCat's answer is completely viable, here's my two bits:
Your constants are supposed to mean something in that particular situation. They likely are magic numbers with some meaning. The best course of actions is to give them a name, if you want make them maintenable. And in newer C++ it allows them to be templates
#include <iostream>
namespace sdd // some_dirty_details
{
/// #brief: Description of the constant
template <class T>
constexpr T some_constant = static_cast<T>(3.0);
}
int main()
{
std::cout << sdd::some_constant<float> << std::endl;
}
I'm writing code for scientific calculation which uses trigonometric functions, and since I need to use not only float/double but also multiprecision floating point numbers, I'm templatizing the functions and classes.
Let's say I'm simply writing a function to calculate sin(pi*x) * cos(pi*x):
template <class Real>
Real sincos(const Real& x);
How can I use proper versions of trigonometric functions and pi value? Multiprecision floating point libraries usually have their own version of trigonometric functions, and std:: versions are defined only for float, double, and long double, and M_PI is not even standard.
I tried putting function pointers as arguments, but std:: versions are overloaded functions not template, so I should put it like (double (*)(double)&std::sin) which hurts readability and it's hard to use.
template <class Real>
Real sincos(const Real& x,
Real (*sin)(const Real&), Real (*cos)(const Real&), const Real& pi)
{
return sin(pi*x) * cos(pi*x);
}
// I don't think it's well designed function if it's hard to use like this.
double s = sincos<double>(0, (double (*)(double))&std::sin,
(double (*)(double))&std::cos,
M_PI);
my_mpf = sincos<my_mpf>(0, somewhere::my_sin, somewhere::my_cos, my_mpf_version_of_pi);
The problem is that there are lots of math functions needed, so I can not simply put those into the function parameters.
How should I generalize those calculations?
You can consider going the char_traits route.
// default implementation calls std::<stuff>
template<class T>
struct trig_traits {
static constexpr T pi() { return T(3.14159265359); }
static auto sin(T v) { return std::sin(v); }
static auto cos(T v) { return std::cos(v); }
// etc.
};
You can then specialize trig_traits<my_mpf> as needed. Your actual function template will then look like
template <class Real>
Real sincos(const Real& x) {
using traits = trig_traits<Real>;
return traits::sin(traits::pi() * x) * traits::cos(traits::pi() * x);
}
My suggestion:
Provide function overloads for the functions that return PI, sin, and cosine for different types. Use template versions whenever it's appropriate.
Implement sincos using a template.
#include <iostream>
#include <cmath>
// Generic implementation of PI().
template <class Real>
Real PI(Real const& dummy)
{
return (Real)M_PI;
}
// Add overloads of PI for your own types.
// Generic implementation of Sine().
template <class Real>
Real Sine(Real const& x)
{
return std::sin(x);
}
// Add overloads of Sine for your own types.
// Generic implementation of Cosine().
template <class Real>
Real Cosine(Real const& x)
{
return std::cos(x);
}
// Add overloads of Cosine for your own types.
// Generic implementation of sincos().
template <class Real>
Real sincos(const Real& x)
{
return Sine(PI(Real{0})*x) * Cosine(PI(Real{0})*x);
}
int main()
{
double s1 = sincos<double>(0.2);
float s2 = sincos<float>(0.15);
std::cout << "s1: " << s1 << std::endl;
std::cout << "s2: " << s2 << std::endl;
}
Output:
s1: 0.475528
s2: 0.404509
The following pattern will look both in namespace std and the argument-dependent namespace:
template<typename T>
T sincos(T x)
{
using namespace std;
return sin(x) * cos(x);
}
This does assume that the relevant types were implemented properly, i.e. in their own namespace with the standard names for the operators. If not you might need to do the wrapping:
namespace myReals
{
using Real = ::myReal;
using cos = ::myRealCos;
using sin = ::myRealSin;
}
I am attempting to recreate the Observer pattern where I can perfectly forward parameters to a given member function of the observers.
If I attempt to pass the address of a member function which has multiple overrides, it cannot deduce the correct member function based on the arguments.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Class>
struct observer_list
{
template<typename Ret, typename... Args, typename... UArgs>
void call(Ret (Class::*func)(Args...), UArgs&&... args)
{
for (auto obj : _observers)
{
(obj->*func)(std::forward<UArgs>(args)...);
}
}
std::vector<Class*> _observers;
};
struct foo
{
void func(const std::string& s)
{
std::cout << this << ": " << s << std::endl;
}
void func(const double d)
{
std::cout << this << ": " << d << std::endl;
}
};
int main()
{
observer_list<foo> l;
foo f1, f2;
l._observers = { &f1, &f2 };
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
return 0;
}
This fails to compile with template argument deduction/substitution failed.
Note that I had Args... and UArgs... because I need to be able to pass parameters which are not necessarily the same type asthe type of the function signature, but are convertible to said type.
I was thinking I could use a std::enable_if<std::is_convertible<Args, UArgs>> call to disambiguate, but I don't believe I can do this with a variadic template parameter pack?
How can I get the template argument deduction to work here?
The issue is here:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
For both lines, the compiler doesn't know which foo::func you are referring to. Hence, you have to disambiguate yourself by providing the type information that is missing (i.e., the type of foo:func) through casts:
l.call(static_cast<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
Alternatively, you can provide the template arguments that the compiler cannot deduce and that define the type of func:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&foo::func, 0.5);
Notice that you have to use double and not const double above. The reason is that generally double and const double are two different types. However, there's one situation where double and const double are considered as if they were the same type: as function arguments. For instance,
void bar(const double);
void bar(double);
are not two different overloads but are actually the same function.
I have a program where I must print many STL vectors on the screen after doing some calculation on each component. So I tried to create a function like this:
template <typename a>
void printWith(vector<a> foo, a func(a)){
for_each(foo.begin(), foo.end(), [func](a x){cout << func(x) << " "; });
}
And then use it like this:
int main(){
vector<int> foo(4,0);
printWith(foo, [](int x) {return x + 1;});
return 0;
}
Unfortunately, I'm having a compiling error about the type of the lambda expression I've put inside the printWith call:
g++ -std=gnu++0x -Wall -c vectest.cpp -o vectest.o
vectest.cpp: In function ‘int main()’:
vectest.cpp:16:41: error: no matching function for call to ‘printWith(std::vector<int>&, main()::<lambda(int)>)’
vectest.cpp:10:6: note: candidate is: void printWith()
make: *** [vectest.o] Error 1
Of course, if I do:
int sumOne(int x) {return x+1;}
then printWith(foo, sumOne); works as intended. I thought the type of a lambda expression would be the type of a function with the inferred return type. I also though that I could fit a lambda anywhere I could fit a normal function. How do I make this work?
The following works for me:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename F>
void printWith(vector<a> foo, F f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Testing:
$ g++-4.5 -std=gnu++0x -Wall test.cpp
$ ./a.out
2 3 4 5 6
Alternatively, you can exploit the fact that closure types with no lambda-capture can be implicitly converted to function pointers. This is closer to your original code and also cuts down on the number of instantiations of the function template (in the original solution you get a new instantiation every time you use the function template with a different function object type; note though that it doesn't matter much in this specific case since the printWith function is very short and most probably will be always inlined):
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, b f(a)){
for_each(foo.begin(), foo.end(), [=](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith<int, int>(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Unfortunately, implicit conversion doesn't play very well with template argument deduction: as you can see, I had to specify template arguments in the call to printWith.
Another alternative is to use std::function. This also helps to minimize the number of template instantiations and works even for lambda expressions with lambda-capture, but has the same problems with template argument deduction:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, std::function<b(a)> f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
int y = 1;
printWith<int, int>(foo, [&](int x) { return x + y; });
std::cout << '\n';
return 0;
}
The reason that you're having a problem is because you're trying to use a function. Free functions have a specific representation (as a function pointer) which is not interchangable with function objects of any kind. Function pointers (which is basically what you have here) should be avoided. You need to take a function object directly with it's type specified by template.
template <typename a, typename Func>
void printWith(vector<a> foo, Func func){
for_each(foo.begin(), foo.end(), [&](a x){cout << func(x) << " "; });
}
Alternatively, take a polymorphic function object such as std::function.
template<typename a>
void printWith(vector<a> foo, std::function<string(const a&)> func) {
for_each(foo.begin(), foo.end(), [&](a x) { cout << func(x) << " "; });
}
void printWith(vector<a> foo, b func(a)){
This is wrong, you can't do that and that makes the compiler not taking account of this code as it's not valid.
You have two ways to fix this :
1) don't ask for a parameter type, just ask for a functor:
void printWith(vector<a> foo, b func ){ // keep the rest of the code the same
The rest of your function will not compile if func don't take a a as parameter anyway.
2) force the functor type:
template <typename a>
void printWith(vector<a> foo, std::function< void (a) > func ){
Then it's like if you were using a function pointer. No (or less) compile-time optimization, but at least you enforce the functor signature. See std::function or boost::function for details.
The reason this doesn't work is that you're mixing template argument deduction with implicit conversions. If you get rid of deduction it works:
printWith<int>(foo, [](int x) {return x + 1;});
However, it would be better (inside printWith) to let func's type be another template parameter, as others recommend.
If on the other hand you really want to add constraints to this type there are better ways to do it using SFINAE (for soft errors) or static_assert (for hard errors).
For instance:
// A constraints metafunction
template<typename T, typename Element>
struct is_element_printer
: std::is_convertible<T, Element (*)(Element)>
{};
Here, is_element_printer<T, Element>::value is true iff T implicitly converts to Element (*)(Element). I'm only using this for illustrative purposes and I cannot recommend it for real use: there are plenty of things that could qualify as an 'element printer' in a lot of situations that are not function pointers. I'm only doing this because std::is_convertible is readily available from <type_traits> and there is no other more obvious test available. You should write your own.
Then:
template<typename Container, typename Functor>
void
printWith(Container&& container, Functor&& functor)
{
// avoid repetition
typedef typename std::decay<Container>::type::value_type value_type;
// Check our constraints here
static_assert(
std::is_element_printer<
typename std::decay<Functor>::type,
value_type
>::value,
"Descriptive error message here"
);
// A range-for is possible instead
std::for_each(container.cbegin(), container.cend(), [&functor](value_type const& v)
{ std::cout << functor(v) << ' '; });
}
I'm looking for the rules involving passing C++ templates functions as arguments.
This is supported by C++ as shown by an example here:
void add1(int &v) { v += 1 }
void add2(int &v) { v += 2 }
template <void (*T)(int &)>
void doOperation()
{
int temp = 0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
Learning about this technique is difficult, however. Googling for "function as a template argument" doesn't lead to much. And the classic C++ Templates The Complete Guide surprisingly also doesn't discuss it (at least not from my search).
The questions I have are whether this is valid C++ (or just some widely supported extension).
Also, is there a way to allow a functor with the same signature to be used interchangeably with explicit functions during this kind of template invocation?
The following does not work in the above program, at least in Visual C++, because the syntax is obviously wrong. It'd be nice to be able to switch out a function for a functor and vice versa, similar to the way you can pass a function pointer or functor to the std::sort algorithm if you want to define a custom comparison operation.
struct add3 {
void operator() (int &v) {v += 3;}
};
...
doOperation<add3>();
Pointers to a web link or two, or a page in the C++ Templates book would be appreciated!
Yes, it is valid.
As for making it work with functors as well, the usual solution is something like this instead:
template <typename F>
void doOperation(F f)
{
int temp = 0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}
which can now be called as either:
doOperation(add2);
doOperation(add3());
See it live
The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)
Template parameters can be either parameterized by type (typename T) or by value (int X).
The "traditional" C++ way of templating a piece of code is to use a functor - that is, the code is in an object, and the object thus gives the code unique type.
When working with traditional functions, this technique doesn't work well, because a change in type doesn't indicate a specific function - rather it specifies only the signature of many possible functions. So:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op(4,5,add);
Isn't equivalent to the functor case. In this example, do_op is instantiated for all function pointers whose signature is int X (int, int). The compiler would have to be pretty aggressive to fully inline this case. (I wouldn't rule it out though, as compiler optimization has gotten pretty advanced.)
One way to tell that this code doesn't quite do what we want is:
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
is still legal, and clearly this is not getting inlined. To get full inlining, we need to template by value, so the function is fully available in the template.
typedef int(*binary_int_op)(int, int); // signature for all valid template params
template<binary_int_op op>
int do_op(int a, int b)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op<add>(4,5);
In this case, each instantiated version of do_op is instantiated with a specific function already available. Thus we expect the code for do_op to look a lot like "return a + b". (Lisp programmers, stop your smirking!)
We can also confirm that this is closer to what we want because this:
int (* func_ptr)(int,int) = add;
int c = do_op<func_ptr>(4,5);
will fail to compile. GCC says: "error: 'func_ptr' cannot appear in a constant-expression. In other words, I can't fully expand do_op because you haven't given me enough info at compiler time to know what our op is.
So if the second example is really fully inlining our op, and the first is not, what good is the template? What is it doing? The answer is: type coercion. This riff on the first example will work:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
float fadd(float a, float b) { return a+b; }
...
int c = do_op(4,5,fadd);
That example will work! (I am not suggesting it is good C++ but...) What has happened is do_op has been templated around the signatures of the various functions, and each separate instantiation will write different type coercion code. So the instantiated code for do_op with fadd looks something like:
convert a and b from int to float.
call the function ptr op with float a and float b.
convert the result back to int and return it.
By comparison, our by-value case requires an exact match on the function arguments.
Function pointers can be passed as template parameters, and this is part of standard C++
. However in the template they are declared and used as functions rather than pointer-to-function. At template instantiation one passes the address of the function rather than just the name.
For example:
int i;
void add1(int& i) { i += 1; }
template<void op(int&)>
void do_op_fn_ptr_tpl(int& i) { op(i); }
i = 0;
do_op_fn_ptr_tpl<&add1>(i);
If you want to pass a functor type as a template argument:
struct add2_t {
void operator()(int& i) { i += 2; }
};
template<typename op>
void do_op_fntr_tpl(int& i) {
op o;
o(i);
}
i = 0;
do_op_fntr_tpl<add2_t>(i);
Several answers pass a functor instance as an argument:
template<typename op>
void do_op_fntr_arg(int& i, op o) { o(i); }
i = 0;
add2_t add2;
// This has the advantage of looking identical whether
// you pass a functor or a free function:
do_op_fntr_arg(i, add1);
do_op_fntr_arg(i, add2);
The closest you can get to this uniform appearance with a template argument is to define do_op twice- once with a non-type parameter and once with a type parameter.
// non-type (function pointer) template parameter
template<void op(int&)>
void do_op(int& i) { op(i); }
// type (functor class) template parameter
template<typename op>
void do_op(int& i) {
op o;
o(i);
}
i = 0;
do_op<&add1>(i); // still need address-of operator in the function pointer case.
do_op<add2_t>(i);
Honestly, I really expected this not to compile, but it worked for me with gcc-4.8 and Visual Studio 2013.
In your template
template <void (*T)(int &)>
void doOperation()
The parameter T is a non-type template parameter. This means that the behaviour of the template function changes with the value of the parameter (which must be fixed at compile time, which function pointer constants are).
If you want somthing that works with both function objects and function parameters you need a typed template. When you do this, though, you also need to provide an object instance (either function object instance or a function pointer) to the function at run time.
template <class T>
void doOperation(T t)
{
int temp=0;
t(temp);
std::cout << "Result is " << temp << std::endl;
}
There are some minor performance considerations. This new version may be less efficient with function pointer arguments as the particular function pointer is only derefenced and called at run time whereas your function pointer template can be optimized (possibly the function call inlined) based on the particular function pointer used. Function objects can often be very efficiently expanded with the typed template, though as the particular operator() is completely determined by the type of the function object.
The reason your functor example does not work is that you need an instance to invoke the operator().
Came here with the additional requirement, that also parameter/return types should vary.
Following Ben Supnik this would be for some type T
typedef T(*binary_T_op)(T, T);
instead of
typedef int(*binary_int_op)(int, int);
The solution here is to put the function type definition and the function template into a surrounding struct template.
template <typename T> struct BinOp
{
typedef T(*binary_T_op )(T, T); // signature for all valid template params
template<binary_T_op op>
T do_op(T a, T b)
{
return op(a,b);
}
};
double mulDouble(double a, double b)
{
return a * b;
}
BinOp<double> doubleBinOp;
double res = doubleBinOp.do_op<&mulDouble>(4, 5);
Alternatively BinOp could be a class with static method template do_op(...), then called as
double res = BinOp<double>::do_op<&mulDouble>(4, 5);
EDIT
Inspired by comment from 0x2207, here is a functor taking any function with two parameters and convertible values.
struct BinOp
{
template <typename R, typename S, typename T, typename U, typename V> R operator()(R (*binaryOp )(S, T), U u, V v)
{
return binaryOp(u,v);
}
};
double subD(double a, int b)
{
return a-b;
}
int subI(double a, int b)
{
return (int)(a-b);
}
int main()
{
double resD = BinOp()(&subD, 4.03, 3);
int resI = BinOp()(&subI, 4.03, 3);
std::cout << resD << std::endl;
std::cout << resI << std::endl;
return 0;
}
correctly evaluates to double 1.03 and int 1
Edit: Passing the operator as a reference doesnt work. For simplicity, understand it as a function pointer. You just send the pointer, not a reference.
I think you are trying to write something like this.
struct Square
{
double operator()(double number) { return number * number; }
};
template <class Function>
double integrate(Function f, double a, double b, unsigned int intervals)
{
double delta = (b - a) / intervals, sum = 0.0;
while(a < b)
{
sum += f(a) * delta;
a += delta;
}
return sum;
}
.
.
std::cout << "interval : " << i << tab << tab << "intgeration = "
<< integrate(Square(), 0.0, 1.0, 10) << std::endl;