The following code compiles fine.
#include <iostream>
struct rgb8{
uint8_t r() const {return 0;};
};
template<typename L, typename P>
L pixelToLevel(P p) {
return static_cast<L>(p);
}
template<>
uint8_t pixelToLevel<uint8_t, rgb8>(rgb8 p) { // <---------- line X
return pixelToLevel<uint8_t, uint8_t>(p.r());
}
int main()
{
pixelToLevel<uint8_t>(rgb8());
return 0;
}
But if in line X I change rgb8 p to const rgb8& p, it fails to compile.
(The exact compiler error generated depends on whether or not the explicit template argument rgb8 is also changed to const rgb8&.)
How can I get it to compile if I want to pass p by reference rather than by value on line X?
You need to change the template parameter in the declaration of specialization, and template argument when calling it too. Otherwise the primary template would be called instead. e.g.
template<>
uint8_t pixelToLevel<uint8_t, const rgb8&>(const rgb8& p) { // <---------- line X
return pixelToLevel<uint8_t, uint8_t>(p.r());
}
then
pixelToLevel<uint8_t, const rgb8&>(rgb8());
LIVE
EDIT
Given pixelToLevel<uint8_t>(rgb8());, template argument deduction is performed with primary template and P is deduced as rgb8 (it won't be deduced as const rgb8& with current primary template's parameter declaration), then the specialization version won't be called.
You can apply overloading instead of template specialization. e.g.
template<typename L, typename P>
L pixelToLevel(P p) {
return static_cast<L>(p);
}
template<typename L>
L pixelToLevel(const rgb8& p) { // <---------- line X
return pixelToLevel<L, uint8_t>(p.r());
}
Then pixelToLevel<uint8_t>(rgb8()); would select the 2nd overload.
LIVE
An alternate solution to #songyuanyao's would be
template<typename L, typename P>
L pixelToLevel(const P& p) {
return static_cast<L>(p);
}
Related
When I use have template function which accepts another function as a parameter, C++ can't derive template parameters. It's very annoying to specify them all the time. How can I define the following function such that I don't have to specify type parameters every time?
#include <functional>
template <typename S, typename T>
T apply(const S& source, const function<T (const S&)>& f) {
return f(source);
}
template <typename S, class Functor, typename T>
T applyFun(const S& source, const Functor& f) {
return f(source);
}
int main() {
// Can't derive T. Why?
apply(1, [](int x) { return x + 1; });
// Compiles
apply<int, int>(1, [](const int& x) { return x + 1; });
// Can't derive T. Kind of expected.
applyFun(1, [](int x) { return x + 1; });
}
It makes sense to me why it can't derive type parameter in the second function, but not in the first one (since x + 1 is int, so it should deduce that T = int).
A template parameter must appear in a function parameter type to be deductible. Moreover lambdas are not functions so, whatsoever the return type of a lambda cannot participate to template argument deduction.
But in this case, there is no need to specify the return type. Return type deduction can do the job:
template <typename S, class Functor>
auto applyFun(const S& source, const Functor& f) {
return f(source);
}
If you can use C++17, you can use the deduction guides for std::function as follows
template <typename S, typename F,
typename T = typename decltype( std::function{std::declval<F>()} )::result_type>
T applyFun (S const & source, F const & f)
{
return f(source);
}
but, as pointed by Oliv, for your example function there is non need of T because you can use auto (from C++14; auto ... -> decltype(f(source)) in C++11).
-- EDIT --
The OP say
The good thing about this solution is that I can use T inside the function (e.g. if I want to implement vector_map).
You can detect and use T, also inside the function, using a using
Something as
template <typename S, typename F>
auto applyFun (S const & source, F const & f)
{
using T = typename decltype( std::function{f} )::result_type;
return f(source);
}
or simpler: using T = decltype( f(source) );.
The OP also observe that
The downside is that for some reason now I can't write [] (const auto& x) { ... } in function call.
Correct.
Because std::function template types can't be deduced from a generic-lambda.
But using the fact that you know the type of the argument, you can use decltype() again
template <typename S, typename F,
typename T = decltype(std::declval<F const>()(std::declval<S const>()))>
T applyFun (S const & source, F const & f)
{ return f(source); }
This solution should works also for C++14 and C++11.
Here is an example case of what I'm trying to do (it is a "test" case just to illustrate the problem) :
#include <iostream>
#include <type_traits>
#include <ratio>
template<int Int, typename Type>
constexpr Type f(const Type x)
{
return Int*x;
}
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template</*An int OR a type*/ Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
int main()
{
std::cout<<f<1>(42.)<<std::endl;
std::cout<<f<std::kilo>(42.)<<std::endl;
}
As you can see, there are two versions of the f() function : the first one takes an int as a template parameter, and the second one takes a std::ratio. The problem is the following :
I would like to "wrap" this function through g() which can take an int OR a std::ratio as first template parameter and call the good version of f().
How to do that without writing two g() functions ? In other words, what do I have to write instead of /*An int OR a type*/ ?
Here's how I would do it, but I've changed your interface slightly:
#include <iostream>
#include <type_traits>
#include <ratio>
template <typename Type>
constexpr
Type
f(int Int, Type x)
{
return Int*x;
}
template <std::intmax_t N, std::intmax_t D, typename Type>
constexpr
Type
f(std::ratio<N, D> r, Type x)
{
// Note use of r.num and r.den instead of N and D leads to
// less probability of overflow. For example if N == 8
// and D == 12, then r.num == 2 and r.den == 3 because
// ratio reduces the fraction to lowest terms.
return x*r.num/r.den;
}
template <class T, class U>
constexpr
typename std::remove_reference<U>::type
g(T&& t, U&& u)
{
return f(static_cast<T&&>(t), static_cast<U&&>(u));
}
int main()
{
constexpr auto h = g(1, 42.);
constexpr auto i = g(std::kilo(), 42.);
std::cout<< h << std::endl;
std::cout<< i << std::endl;
}
42
42000
Notes:
I've taken advantage of constexpr to not pass compile-time constants via template parameters (that's what constexpr is for).
g is now just a perfect forwarder. However I was unable to use std::forward because it isn't marked up with constexpr (arguably a defect in C++11). So I dropped down to use static_cast<T&&> instead. Perfect forwarding is a little bit overkill here. But it is a good idiom to be thoroughly familiar with.
How to do that without writing two g() functions ?
You don't. There is no way in C++ to take either a type or a value of some type, except through overloading.
It is not possible to have a template parameter taking both type and non-type values.
Solution 1:
Overloaded functions.
Solution 2:
You can store values in types. Ex:
template<int n>
struct store_int
{
static const int num = n;
static const int den = 1;
};
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template<typename Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
But with this solution you will have to specify g<store_int<42> >(...) instead of g<42>(...)
If the function is small, I advise you to use overloading.
I need to pass a function to an operator. Any unary function having correct arg type. Return type can be anything. Because this is library code, I can not wrap it or cast f to specific overload (outside of operator*). Function takes operator* 1st arg as it own argument. Artificial example below compiles and returns correct results. But it has hardcoded int return type—to make this example compile.
#include <tuple>
#include <iostream>
using namespace std;
template<typename T>
int operator* (T x, int& (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
cout << tpl * get<0>;
}
Is it possible to make operator* to accept f with arbitrary return type?
UPDATE - GCC bug?
Code:
#include <tuple>
template<typename T, typename U>
U operator* (T x, U& (*f)(T&) ) {
return (*f)(x);
};
int main() {
std::tuple<int,int> tpl(42,43);
return tpl * std::get<0,int,int>;
}
Compiles and runs correctly with gcc462 and 453 but is reject with gcc471 and 480. So it is possible GCC regression bug. I've submitted bug report:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54111
EDIT
I've changed example to use tuple as arg - it was possible trivially deduce return type in previous example.
EDIT2
Many people could not understand what is needed, so I've changed call function to operator* to make example more real.
Yes, if this is what you mean:
template<typename T, typename F>
auto call (T x, F f) -> decltype(f(x)) {
return (f)(x);
}
There are actually a lot of ways to do that.
As an answer to your updated question:
as discussed by #DavidRodríguez, get<0> is not enough, nor the syntatically correct &get<0>. What you need is &get<0,int,int>. Follows your example, it would be:
#include <tuple>
using namespace std;
template<typename T, typename U>
U call (T x, U (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
call(tpl, &get<0,int,int>);
return 0;
}
During normal use of std::get<>(), the int,int part is deduced automatically. But in your situation you need to provide it, since there is no parameters. One workaround is a custom get template function:
#include <tuple>
using namespace std;
template <size_t I, typename T>
auto myGet(T& tpl) -> decltype(get<I>(tpl))
{
return get<I>(tpl);
}
template<typename T, typename U>
U call (T x, U (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
auto get0 = &myGet<0, decltype(tpl)>;
call(tpl, get0);
// call(tpl, &myGet<0, decltype(tpl)>); // all in one line, do not work
return 0;
}
You should be able to do this:
template<typename T,typename U>
U call (T x, U (*f)(T) ) {
return (*f)(x);
};
Here, the context of polymorphic is expecting 'Derived' from 'Base&.
Given
class P { };
class Q : public P { };
auto operator + (const P& p, int x) -> DYNAMIC_DECLTYPE(P) {
DYNAMIC_DECLTYPE(P) p2(p);
p2.func(x);
return p2;
}
Is there a way to have DYNAMIC_DECLTYPE working? I want to use this form instead of
template <typename T> T operator + (const T& t, int x)
or have a potentially long list of
if (!strcmp(typeid(p).name(), typeid(derived()).name()) { ... }
because the latter cannot be used to restrict T to P or subclasses thereof (prove me wrong, if possible).
What you are trying to do is in every sense of the word a template pattern: You have an unbounded family of return types with matching function argument types. This should simply be a straight template.
If you want to restrict the permissible types, you should add some typetrait magic. Perhaps like this:
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_base_of<P, T>::value, T>::type
operator+(T const & t, int x)
{
T s(t);
s.func(x);
return s;
}
(If func returns a reference, you can shortcut this to return T(t).func(x);.)
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.