struct F
{
int operator()(int a, int b) { return a - b; }
bool operator()(long a, long b) { return a == b; }
};
F f;
int x = 104;
bind<int>(f, _1, _1)(x); // f(x, x), i.e. zero
Some compilers have trouble with the bind(f, ...) syntax. For portability reasons, an alternative way to express the above is supported:
boost::bind(boost::type<int>(), f, _1, _1)(x);
like above, the code use a boost::type for function object type,
I to know where contain the boost::type implementation?
I looked around and found the definition below.
// type.hpp
namespace boost {
// Just a simple "type envelope". Useful in various contexts, mostly to work
// around some MSVC deficiencies.
template <class T>
struct type {};
}
Related
I was wondering if it was possible to use fact that in
struct Foo
{
int x;
};
int main()
{
Foo foo;
auto [a0] = foo;
auto [a1, b1] = foo;
auto [a2, b2, c2] = foo;
// auto [a, b, c, ...] = foo;
}
only the first structured-binding is valid, in order to create metafunction that takes any pod type and returns a tuple consisting of all the member types of the passed pod, e.g. for Foo it would return
std::tuple<int>
I tried something like this, but that didn't work out:
#include <tuple>
#include <type_traits>
#include <utility>
using namespace std;
template<typename T, typename U = void>
struct to_tuple;
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()));
};
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()));
};
template<typename T>
using to_tuple_t = typename to_tuple<T>::type;
struct Bar1
{
int x;
};
struct Bar2
{
int x;
float y;
};
int main()
{
static_assert(is_same_v<to_tuple_t<Bar1>, tuple<int>>);
static_assert(is_same_v<to_tuple_t<Bar2>, tuple<int, float>>);
}
The main issue here is that a structured bindings declaration is just that -- a declaration. We cannot form a "structured binding expression" in order to get the type, which is required in metaprogramming to constrain a template (for e.g., the void_t pattern, or a concept/requires clause)
Per [dcl.struct.bnd], despite the presence of an assignment-expression, a structured binding is distinctly a declaration.
Template metaprogramming relies on types, and a declaration is without a type.
You cannot for example say decltype(int a = 10) or even decltype(int a) for this reason.
You can say decltype(int{}) because now we have an expression.
For this reason, your void_t pattern does not work.
Unfortunately concepts/constraints don't help us, because we cannot have a declaration inside a requires clause (per [gram.expr])
Personally I think it's a bit of an oversight that we cannot have the equivalent of int{} for structured bindings. But then again, reflection is on its way anyway, so the point is probably moot.
Edit: As dfri pointed out, there is a GNU extension called statement expressions that can make this possible (as an extension it is understandably not portable code)
Suppose I have the following definitions:
int f(int ) { return 1; } // a)
template<typename T> int f(T x) { return 2; } // b)
I understand that if I call f, e.g. f(1), the non-template overload a) will be preferred, but is there a way to unambiguously refer to a)? For instance, I can use f<int> to refer to b) unambiguously.
As an example of why this would be useful, consider the following function:
template<typename Func, typename T> void print_result(Func f, T arg)
{
std::cout << f(arg) << std::endl;
}
If I try to use it on f, e.g, print_result(f,1), I get a compilation error (the compiler does not know which f I mean). I can use print_result(f<int>,1) to tell it to use b), but how do I tell it to use a) ?
I found I can use print_result(static_cast<int (*)(int)>(f), 1), but this feels hacky and is cumbersome. Is there a better way?
use template specialization:
template<>
int f<int>(int x ) { return 1; } // a)
My program generates random strings that have a "type" and an identifier. Like so:
float lHTY8Au8b9 = float();
int dO3PNUInH6 = int();
float B_MtShimak = float();
float hgi_TzaVEv = float();
double mfW8kr6h6q = double();
std::string lSLj9antfj = std::string();
char MQkeARWYTL = char();
char Oe7G_ZRJy6 = char();
float qUwmOWeilK = float();
double FJYIODwQfx = double();
Then I have the following to see if two arbitrary variables can be added:
template <typename A, typename B>
typename std::enable_if<std::is_convertible<A, B>::value, decltype(A() + B())>::type
try_to_add(A a, B b) {
return a + b;
}
Of course, it works because I get the following error:
main.cpp:51:54: error: no matching function for call to ‘try_to_add(double&, std::string&)’
try_to_add<double,std::string>(mfW8kr6h6q,lSLj9antfj);
However what I want instead is a list of candidates that don't cause a compile error. I can't hardcode the template parameters because it only accepts ints, and I cannot check inside the generator program because they're just strings, and attempting to use try_to_add with non-convertible types will cause a compile error. I know that SFINAE is the wrong approach, but is there a way to get try_to_add to simply do nothing, rather than generate a compile error?
Coliru
Add another overlaod with the inverse condition that does nothing.
template <typename A, typename B>
typename std::enable_if<!std::is_convertible<A, B>::value>::type
try_to_add(A, B) { }
Here is a few useful techniques. First, instead of is_convertible, we just try adding. if it works, bonus. Second, I use perfect forwarding.
Finally, I use a variardic pack for the "does work" catch-all. This is the sink technique.
#include <iostream>
#define RETURNS(X) ->decltype(X) { return (X); }
template<typename A, typename B>
auto try_to_add(A&& a, B&& b)
RETURNS( std::forward<A>(a) + std::forward<B>(b) )
template<typename... Ts>
void try_to_add( Ts&&... ) {
std::cout << "failed to add\n";
}
struct foo {};
int main() {
int a =1, b=2;
std::cout << try_to_add( a, b ) << "\n";
try_to_add( a, foo{} );
}
The RETURNS macro works around the lack of automatic return type deduction in C++11. In C++1y we will have a better option that lets us omit the repeated -> (X) { returns (X); } annoyance.
The point of the variardic args is that such a pack will only match if all overloads without the variardic args fail to match (they are considered last). This is useful because you don't have to maintain the bool condition in two different spots at once (once inverted).
The RETURNS macro can be expanded:
template<typename A, typename B>
auto try_to_add(A&& a, B&& b)
-> decltype( std::forward<A>(a) + std::forward<B>(b) )
{ return ( std::forward<A>(a) + std::forward<B>(b) ); }
if you prefer not to use macros (which is understandable).
Here are two template functions, that differ only in their template parameters. The rest of the parameters are exactly the same.
template<int module>
void template_const(int &a,int & b){
a = a & module;
b = b % module;
}
template<bool x>
void template_const(int &a,int & b){
int w;
if (x){
w = 123;
}
else w = 512;
a = a & w;
b = b % w;
}
When I try to call them like this
template_const<true>(a,b)
or
template_const<123>(a,b)
the compiler tells me that the call is ambiguous. How can I call these two functions?
As #jogojapan pointed out, the problem is that the compiler cannot order these two functions, i.e. there is not one that is more specialized than the other. As explained in §14.5.6.2, when a call to an overloaded function template is ambiguous, the compiler uses a partial ordering between the various overloads to select the most specialized one.
To order the overloads, the compiler transforms each one of them and performs template argument deduction to see if one is more specialized than another one (there is a short explanation at the end of this answer). In your case, the two overloads are equivalent (or not comparable): template<int> void template_const(int &,int &) is not more specialized than template<bool> void template_const(int &, int &), and vice-versa.
Therefore, the compiler cannot select one over the other, hence generating an ambiguous call error.
If you are ok with explicitely specifying the type of the parameter you want to pass, you can use partial template specialization as follow:
template<typename T, T param>
struct template_const_impl;
template <int module>
struct template_const_impl<int, module>
{
static void apply(int &a, int &b)
{
a = a & module;
b = b % module;
}
};
template<bool x>
struct template_const_impl<bool, x>
{
static void apply(int &a, int &b)
{
const int w = x ? 123 : 512;
a = a & w;
b = b % w;
}
};
template <typename T, T param>
void template_const(int &a, int &b)
{
return template_const_impl<T, param>::apply(a, b);
}
int main()
{
int i = 512, j = 256;
template_const<int, 123>(i, j);
template_const<bool, true>(i, j);
}
This is not ideal, but it don't think there is a cleaner solution unless you can use C++11 and are willing to rely on some macros, in which case you can simplify the calling code a bit (idea taken from #Nawaz in this answer):
#define TEMPLATE_CONST(x) template_const<decltype(x), x>
int main()
{
int i = 512, j = 256;
TEMPLATE_CONST(123)(i, j);
TEMPLATE_CONST(true)(i, j);
}
I do not think it is going to work like this. You have overloads with same parameter types. Probably you will have to give them different names in the end and call them as you tried.
Is it somehow possible to reflect the type of the argument of a function at compile time?
So that
int b = add(3, 6)
Would result in a template instantiation in the form of
int add(int a, int b) { return a + b }
out of some however declared function template
A add(A a, B b) { return a + b }
I don't know if that is possible with templates they do not really seem to be made for heavy meta-programming.
template<typename T>
T add(T a, T b) { return a + b; }
Then you can call this with any built-in type (int, short, double, float, etc), and it will instantiate the function add at compile time, according to the type you use.
Note that if you split this into header/source, you will have trouble:
add.h:
template<typename T>
T add(T a, T b);
add.cpp:
template<typename T>
T add(T a, T b) { return a + b; }
main.cpp:
#include "add.h"
int a = 3;
int b = 5;
int i = add(a, b);
When you try to compile this, it will fail at link time. Here's why.
Compiling add.obj does not instantiate the add template method -- because it's never called in add.cpp. Compiling main.obj instantiates the function declaration -- but not the function body. So at link time, it will fail to find the definition of the add method.
Simplest fix is to just put the entire template function in the header:
add.h:
template<typename T>
T add(T a, T b) { return a + b; }
and then you don't even need the add.cpp file at all.
Doesn't this do what you're asking?
template <typename A, typename B>
A add(A a, B b) { return a + b; }
This is hardly "heavy meta-programming".
This is exactly the sort of thing templates do.
template <typename T>
inline T add(T a, T b) { return a + b; }
Allowing two different types gets a little bit trickier but is also possible.
If you plan on using anything other than simple types you want (in a header file):
template <typename A>
inline A add(const A& a, const A& b) { return a + b; }
Note the 'inline'.
As noted by others, the issue with mixed types is how to determine the return type from the argument types. Suppose we stick to simple types and have:
template
inline A add(A a, B b) { return a + b; }
Then this fails (likely with only a warning):
double d = add(1, 1.5); // Sets d to 2.0
So you have to do some work. For example:
template<class A, class B>
struct Promote
{
};
template<class A>
struct Promote<A,A>
{
typedef A Type;
};
template<>
struct Promote<int, double>
{
typedef double Type;
};
template<>
struct Promote<double, int>
{
typedef double Type;
};
The add function becomes:
template<class A, class B>
inline typename Promote<A,B>::Type add(A a, B b)
{
return a + b;
}
What all this does for you is ensure that the return type is the one you specify for adding a given pair of types. This will work even for complex types.
Templates do all their magic at compile time, but that seems to be quite adequate for what you're asking:
template <class T>
T add(T a, T b) { return a + b; }
It does get a bit more complex when the two might not match, so (for example) you could add an int to a double and get a double result. The current standard doesn't really support that1; with C++0x you can look into auto and decltype for such tasks.
1Though Boost typeof will often do the job.