For some strange reason, I can't get the template arguments in this one piece of code to implicitly cast to a compatible type.
#include <type_traits>
template <typename T, unsigned D>
struct vec;
template <>
struct vec<float, 2> {
typedef float scalar;
static constexpr unsigned dimension = 2;
float x, y;
float& operator[] (unsigned i) { return (&x)[i]; }
float const& operator[] (unsigned i) const { return (&x)[i]; }
};
template <typename L, typename R>
struct add;
template <typename L, typename R, unsigned D>
struct add<vec<L, D>, vec<R, D>> {
typedef vec<L, D> left_type;
typedef vec<R, D> right_type;
typedef vec<typename std::common_type<L, R>::type, D> return_type;
add(left_type l, right_type r)
: left(l),
right(r)
{}
operator return_type() const
{
return_type result;
for (unsigned i = 0; i < D; ++i)
result[i] = left[i] + right[i];
return result;
}
left_type left;
right_type right;
};
template <typename L, typename R, unsigned D>
add<vec<L, D>, vec<R, D>>
operator+(vec<L, D> const& lhs, vec<R, D> const& rhs)
{
return {lhs, rhs};
}
int main()
{
vec<float, 2> a, b, c;
vec<float, 2> result = a + b + c;
}
Fails with:
prog.cpp: In function 'int main()':
prog.cpp:55:36: error: no match for 'operator+' in 'operator+ [with L = float, R = float, unsigned int D = 2u](((const vec<float, 2u>&)((const vec<float, 2u>*)(& a))), ((const vec<float, 2u>&)((const vec<float, 2u>*)(& b)))) + c'
So if I'm correct, the compiler should see the code in the main function as this:
((a + b) + c)
compute a + b
cast the result of a + b from add<...> to vec<float, 2> using the conversion operator in add<...>
compute (a + b) + c
But it never does the implicit cast. If I explicitly cast the result of (a + b) to a vec, the code works fine.
I'm going to side-step your actual problem and instead make a recommendation: Rather than writing all of this complicated boilerplate from scratch, have a look at Boost.Proto, which has taken care of all the tricky details for you:
Proto is a framework for building Domain Specific Embedded Languages in C++. It provides tools for constructing, type-checking, transforming and executing expression templates. More specifically, Proto provides:
An expression tree data structure.
A mechanism for giving expressions additional behaviors and members.
Operator overloads for building the tree from an expression.
Utilities for defining the grammar to which an expression must conform.
An extensible mechanism for immediately executing an expression template.
An extensible set of tree transformations to apply to expression trees.
See also the library author's Expressive C++ series of articles, which more-or-less serve as an (excellent) in-depth Boost.Proto tutorial.
Most conversions are not used during template argument deduction.
You rely on template argument deduction when you call your operator+ overload: it is only callable where both arguments are of type vec<...>, but when you try to call it the left-hand argument is of type add<...>. The compiler is not able to figure out that you really mean for that overload to be called (and it isn't allowed to guess), hence the error.
Related
I'm trying to create a visitor function that will add together values of my boost::variant. I am using templates for the case where the types are different for example int + float
typedef boost::variant<int, float> Values;
struct Add : public boost::static_visitor<Values> {
template <typename T, typename U>
auto operator() (T a, U b) const -> decltype(a + b) {
return a + b;
}
}
This compiles and works fine
std::cout << boost::apply_visitor(Add{}, (Values)2, (Values)5) << std::endl;
std::cout << boost::apply_visitor(Add{}, (Values)2, (Values)5.123) << std::endl;
7
7.123
However I also want to add a std::string into the Values variant, so I can also add together strings. I am aware that it is not possible to do string + int for example, but I will make sure that both of Values is a string before attempting to run them through the visitor.
typedef boost::variant<int, float, std::string> Values;
std::cout << boost::apply_visitor(Add{}, (Values)"hello", (Values)"world") << std::endl;
However the program does not compile, giving me the error:
Failed to specialize function template 'unknown-type Add::operator ()(T,U) const'
I know that std::string is a object and not a type and therefore this error kind of makes sense, so I'm trying to make a special case by overloading operator in the Add struct for when the inputs are both strings:
auto operator() (std::string a, std::string b) const {
return a + b;
}
However I get the error
std::basic_string,std::allocator> Add::operator ()(std::string,std::string) const': cannot convert argument 1 from 'T' to 'std::string'
It looks like it's still trying to run the string argument through the templated visitor. Where am I going wrong? Is there a better way to achieve what I'm trying to do altogether? Sorry if the answer is obvious I'm still fairly new to C++, boost and templates.
apply_visitor should handle all combinations (even you invalid one).
You might do:
using Values = boost::variant<int, float, std::string>;
// Helper for overload priority
struct low_priority {};
struct high_priority : low_priority{};
struct Add : public boost::static_visitor<Values> {
template <typename T, typename U>
auto operator() (high_priority, T a, U b) const -> decltype(Values(a + b)) {
return a + b;
}
template <typename T, typename U>
Values operator() (low_priority, T, U) const {
// string + int, float + string, ...
throw std::runtime_error("Incompatible arguments");
}
template <typename T, typename U>
Values operator() (T a, U b) const {
return (*this)(high_priority{}, a, b);
}
};
I am new to C++ and currently trying to understand how template functions work. First I wanted to add two numerical values of the same type, which is quite easy to understand.
template <typename T>
T add(T a, T b){return a+b;}
int main(){
float a_f=2.5;float b_f=1.5;float c_f;
int a_i=2;int b_i=1;int c_i;
c_f = add(a_f, b_f);
c_i = add(a_i, b_i);
return 0;
}
Next I wanted to add two numerical numbers with different and equal types. My naive assumption was this:
template<typename R, typename S, typename T>
R add(S a, T b){return a+b;}
int main(){
float a=3.2; int b=2;
auto result1 = add(a,b); // error: no matching function for call to ‘add(float&, int&)’
auto result2 = add(a,a); // error: no matching function for call to ‘add(float&, float&)’
auto result3 = add(b,b); // error: no matching function for call to ‘add(int&, int&)’
return 0;
}
I am aware that this approach is not correct, because the typename's share an intersection regarding data types and therefore the declaration itself cannot be correct.
How could a simple add() function be implemented that adds two numeric values together, regardless of type?
The problem is not with an intersection, but that it cant deduce R. In
template<typename R, typename S, typename T>
R add(S a, T b){return a+b;}
There is nothing telling the compiler what R should be. It's not deduced from the variable you are assigning the result to and you do not specify it, so there is no valid call that it can do. To fix this you can just get rid of R and use the auto return type to have it deduced for you like
template<typename S, typename T>
auto add(S a, T b){return a+b;}
How could a simple add() function be implemented that adds two numeric values together, regardless of type?
In C++14:
template<class T, class U>
auto add(T t, U u) {
return t + u;
}
In the above, the type of the return value is deduced from the type of expression t + u.
C++11 doesn't deduce return types but allows for trailing return type, so a C++11 version is:
template<class T, class U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
What you want is to deduce the return type. However, type deduction for type template parameter only apply for function parameter.
Even though typenames are not the right tool to do that, C++ offers other mean to deduce the type.
Use auto
You can simply put auto there and let the compiler deduce from the return type:
template<typename S, typename T>
auto add(S a, T b){ return a + b; }
Use trailing return types
You can also use the trailing return type if you want to be more explicit on the return type of the function:
template<typename S, typename T>
auto add(S a, T b) -> decltype(a + b) { return a + b; }
This poly_eval function will compute the result of evaluating a polynomial with a particular set of coefficients at a particular value of x. For example, poly_eval(5, 1, -2, -1) computes x^2 - 2x - 1 with x = 5. It's all constexpr so if you give it constants it will compute the answer at compile time.
It currently uses recursive templates to build the polynomial evaluation expression at compile time and relies on C++14 to be constexpr. I was wondering if anybody could think of a good way to remove the recursive template, perhaps using C++17. The code that exercises the template uses the __uint128_t type from clang and gcc.
#include <type_traits>
#include <tuple>
template <typename X_t, typename Coeff_1_T>
constexpr auto poly_eval_accum(const X_t &x, const Coeff_1_T &c1)
{
return ::std::pair<X_t, Coeff_1_T>(x, c1);
}
template <typename X_t, typename Coeff_1_T, typename... Coeff_TList>
constexpr auto poly_eval_accum(const X_t &x, const Coeff_1_T &c1, const Coeff_TList &... coeffs)
{
const auto &tmp_result = poly_eval_accum(x, coeffs...);
auto saved = tmp_result.second + tmp_result.first * c1;
return ::std::pair<X_t, decltype(saved)>(tmp_result.first * x, saved);
}
template <typename X_t, typename... Coeff_TList>
constexpr auto poly_eval(const X_t &x, const Coeff_TList &... coeffs)
{
static_assert(sizeof...(coeffs) > 0,
"Must have at least one coefficient.");
return poly_eval_accum(x, coeffs...).second;
}
// This is just a test function to exercise the template.
__uint128_t multiply_lots(__uint128_t num, __uint128_t n2)
{
const __uint128_t cf = 5;
return poly_eval(cf, num, n2, 10);
}
// This is just a test function to exercise the template to make sure
// it computes the result at compile time.
__uint128_t eval_const()
{
return poly_eval(5, 1, -2, 1);
}
Also, am I doing anything wrong here?
-------- Comments on Answers --------
There are two excellent answers down below. One is clear and terse, but may not handle certain situations involving complex types (expression trees, matrices, etc..) well, though it does a fair job. It also relies on the somewhat obscure , operator.
The other is less terse, but still much clearer than my original recursive template, and it handles types just as well. It expands out to 'cn + x * (cn-1 + x * (cn-2 ...' whereas my recursive version expands out to cn + x * cn-1 + x * x * cn-2 .... For most reasonable types they should be equivalent, and the answer can easily be modified to expand out to what my recursive one expands to.
I picked the first answer because it was 1st and its terseness is more within the spirit of my original question. But, if I were to choose a version for production, I'd choose the second.
Using the power of comma operator (and C++17 folding, obviously), I suppose you can write poly_eval() as follows
template <typename X_t, typename C_t, typename ... Cs_t>
constexpr auto poly_eval (X_t const & x, C_t a, Cs_t const & ... cs)
{
( (a *= x, a += cs), ..., (void)0 );
return a;
}
trowing away poly_eval_accum().
Observe that the first coefficient if explicated, so you can delete also the static_assert() and is passed by copy, and become the accumulator.
-- EDIT --
Added an alternative version to solve the problem of the return type using std::common_type a decltype() of an expression, as the OP suggested; in this version a is a constant reference again.
template <typename X_t, typename C_t, typename ... Cs_t>
constexpr auto poly_eval (X_t const & x, C_t const & c1, Cs_t const & ... cs)
{
decltype(((x * c1) + ... + (x * cs))) ret { c1 };
( (ret *= x, ret += cs), ..., (void)0 );
return ret;
}
-- EDIT 2 --
Bonus answer: it's possible avoid the recursion also in C++14 using the power of the comma operator (again) and initializing an unused C-style array of integers
template <typename X_t, typename C_t, typename ... Cs_t>
constexpr auto poly_eval (X_t const & x, C_t const & a, Cs_t const & ... cs)
{
using unused = int[];
std::common_type_t<decltype(x * a), decltype(x * cs)...> ret { a };
(void)unused { 0, (ret *= x, ret += cs)... };
return ret;
}
A great answer is supplied above, but it requires a common return type and will therefore not work if you are, say, building a compile time expression tree.
What we need is some way to have a fold expression that both does the multiply with the value at the evaluation point x and add a coefficient at each iteration, in order to eventually end up with an expression like: (((c0) * x + c1) * x + c2) * x + c3. This is (I think) not possible with a fold expression directly, but we can define a special type that overloads a binary operator and does the necessary calculations.
template<class M, class T>
struct MultiplyAdder
{
M mul;
T acc;
constexpr MultiplyAdder(M m, T a) : mul(m), acc(a) { }
};
template<class M, class T, class U>
constexpr auto operator<<(const MultiplyAdder<M,T>& ma, const U& u)
{
return MultiplyAdder(ma.mul, ma.acc * ma.mul + u);
}
template <typename X_t, typename C_t, typename... Coeff_TList>
constexpr auto poly_eval(const X_t &x, const C_t &a, const Coeff_TList &... coeffs)
{
return (MultiplyAdder(x, a) << ... << coeffs).acc;
}
As a bonus, this solution also ticks C++17's 'automatic class template argument deduction' box ;)
Edit: Oops, argument deduction wasn't working inside MultiplyAdder<>::operator<<(), because MultiplyAdder refers to its own template-id rather than its template-name. I've added a namespace specifier, but that unfortunately makes it dependent on its own namespace. There must be a way to refer to its actual template-name, but I can't think of any without resorting to template aliases.
Edit2: Fixed it by making operator<<() a non-member.
Consider the following function that computes the integral or floating-point modulo depending on the argument type, at compile-time:
template<typename T>
constexpr T modulo(const T x, const T y)
{
return (std::is_floating_point<T>::value) ? (x < T() ? T(-1) : T(1))*((x < T() ? -x : x)-static_cast<long long int>((x/y < T() ? -x/y : x/y))*(y < T() ? -y : y))
: (static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(x)
%static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(y));
}
Can the body of this function be improved ? (I need to have a single function for both integer and floating-point types).
Here's one way to clean this up:
#include <type_traits>
#include <cmath>
template <typename T> // integral? floating point?
bool remainder_impl(T a, T b, std::true_type, std::false_type) constexpr
{
return a % b; // or whatever
}
template <typename T> // integral? floating point?
bool remainder_impl(T a, T b, std::false_type, std::true_type) constexpr
{
return std::fmod(a, b); // or substitute your own expression
}
template <typename T>
bool remainder(T a, T b) constexpr
{
return remainder_impl<T>(a, b,
std::is_integral<T>(), std::is_floating_point<T>());
}
If you try and call this function on a type that's not arithmetic, you'll get a compiler error.
I would rather define it this way (template aliases + template overloading):
#include <type_traits>
using namespace std;
// For floating point types
template<typename T, typename enable_if<is_floating_point<T>::value>::type* p = nullptr>
constexpr T modulo(const T x, const T y)
{
return (x < T() ? T(-1) : T(1)) * (
(x < T() ? -x : x) -
static_cast<long long int>((x/y < T() ? -x/y : x/y)) * (y < T() ? -y : y)
);
}
// For non-floating point types
template<typename T>
using TypeToCast = typename conditional<is_floating_point<T>::value, int, T>::type;
template<typename T, typename enable_if<!is_floating_point<T>::value>::type* p = nullptr>
constexpr T modulo(const T x, const T y)
{
return (static_cast<TypeToCast<T>>(x) % static_cast<TypeToCast<T>>(y));
}
int main()
{
constexpr int x = modulo(7.0, 3.0);
static_assert((x == 1.0), "Error!");
return 0;
}
It is lengthier but cleaner IMO. I am assuming that by "single function" you mean "something that can be invoked uniformly". If you mean "a single function template", then I would just keep the template alias improvement and leave the overload. But then, as mentioned in another answer, it would not be clear why you do need to have one single function template.
You ask,
“Can the body of this function be improved?”
Certainly. Right now it is a spaghetti mess:
template<typename T>
constexpr T modulo(const T x, const T y)
{
return (std::is_floating_point<T>::value) ? (x < T() ? T(-1) : T(1))*((x < T() ? -x : x)-static_cast<long long int>((x/y < T() ? -x/y : x/y))*(y < T() ? -y : y))
: (static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(x)
%static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(y));
}
You clarify that …
“(I need to have a single function for both integer and floating-point types)”
Well the template is not a single function. It’s a template. Functions are generated from it.
This means your question builds on a false assumption.
With that assumption removed, one way to simplify the function body, which you should do as a matter of course, is to specialize the template for floating point types versus other numeric types. To do that put the function template implementation in a class (because C++ does not support partial specialization of functions, only of classes).
Then you can employ various formatting tricks, including the "0?0 : blah" trick to make the function more readable, with lines and indentation and stuff! :-)
Addendum: delving into your code I see that you cast haphazardly to long int and int with disregard of the invoker's types. That's ungood. It is probably a good idea to write up a bunch of automated test cases, invoking the function with various argument types and big/small values.
template <class T>
constexpr
T
modulo(T x, T y)
{
typedef typename std::conditional<std::is_floating_point<T>::value,
int,
T
>::type Int;
return std::is_floating_point<T>() ?
x - static_cast<long long>(x / y) * y :
static_cast<Int>(x) % static_cast<Int>(y);
}
I believe there is simpler:
// Special available `%`
template <typename T, typename U>
constexpr auto modulo(T const& x, U const& y) -> decltype(x % y) {
return x % y;
}
Note: based on detection of % so also works for custom types as long as they implement the operator. I also made it mixed type while I was at it.
// Special floating point
inline constexpr float modulo(float x, float y) { return /*something*/; }
inline constexpr double modulo(double x, double y) { return /*something*/; }
inline constexpr long double modulo(long double x, long double y) { return /*something*/; }
Note: it would cleaner to have fmod available unfortunately I do not believe it is constexpr; therefore I chose to have non-template modulos for the floating point types which allows you to perform magic to compute the exact modulo possibly based on the binary representation of the type.
You can do that much simpler if you want:
template<typename A, typename B>
constexpr auto Modulo(const A& a, const B& b) -> decltype(a - (b * int(a/b)))
{
return a - (b * int(a/b));
}
I have this template function:
template <class P>
double Determinant(const P & a, const P & b, const P & c) {
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
but I want to avoid forcing the return type to double all the time -- P::x and P::y could be ints too, and I need this function in both situations. Is there a way to specify the type of x and y, something like this?
//doesn't compile; can't deduce template argument for T
template <typename T, class P>
T Determinant(const P & a, const P & b, const P & c) {
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
edit: My compiler is VC2005
edit2: sorry to forget to mention: Unfortunately I can't modify the implementation of the structs for P; one of the point types I deal with is MFC/ATL's CPoint, which are hard-coded as { long x; long y; }.
Compiler cannot deduce return-type of function template, from function argument. Type deduction is done with function arguments only.
In C++03, you can define typedef in your class as:
struct A //suppose A is going to be type argument to your function template
{
int x, y; //I'm assuming type of x and y is same!
typedef int value_type; //type of x and y!
};
And then you've to re-write your function as:
template <class P>
typename P::value_type Determinant(const P & a, const P & b, const P & c) {
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
Notice the return-type now, its a dependent type. Its :
typename P::value_type
The keyword typename is required here.
Alright, as you said you can't modify your structs, then you can use traits instead. Here is how this can be done:
template<typename T> struct PTraits;
//Suppose this is your type which you can't modify
struct A //A is going to be type argument to your function template
{
long x, y;
};
//specialization: defining traits for struct A
template<>
struct PTraits<A>
{
typedef long value_type; //since type of A::x and A::y is long!
};
And your function template would look like this:
template <class P>
typename PTraits<P>::value_type Determinant(const P & a, const P & b, const P & c) {
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
Notice the return-type; its slightly different now:
typename PTraits<P>::value_type
Again, value_type is a dependent name, so the keyword typename is required.
Note that you've to specialize PTraits<> for each type which you pass to the function template, as I did.
I like to use a traits style approach to this:
template<typename T> struct DeterminantReturnInfo {};
template<> struct DeterminantReturnInfo<MyType> { typedef MyOtherType ReturnType; }
template< typename T >
typename DeterminantReturnInfo<T>::ReturnType Determinant( const P & a, const P & B, const P & c)
{
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
If you want it to default to double then you just add typedef double ReturnType; to the initial template.
If you're using Visual Studio 2010 or GCC 4.5+, you can use the trailing return type form:
template<class P>
auto fun(const P& a) -> decltype(a.x + a.y){
return a.x + a.y;
}
Thanks to decltype we automatically get the right return type. Also, the computation is still only done once in the body, not in the trailing return.
Check your return Type its of type member variable x/y . You might not returning so type T.