SFINAE with functions and emulating partial template specialization - c++

I am trying to make a function X that specializes when a member function Y is provided and if the member function Y is not provided the function X uses the global non member function Y to achieve the same effect.
I am currently trying to achieve this with the following code
template <typename Container, typename std::enable_if_t<std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return std::forward<Container>().y();
}
template <typename Container, typename std::enable_if_t<!std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return y(std::forward<Container>(container);
}
But in the case when the container has both a member function y and the global non member function y also works on it. There is a compile error because for the second version of the function the template argument is ill formed because a member function y is needed.
Any idea how I can go about resolving this issue?
NOTE: This is different from just detecting whether a class has a function of a given signature. Sorry if the question seems to ask that! The accepted answer below should make my intention clearer.

The typical approach is to dispatch to a pair of functions where one is preferred if your condition is met and the other is simply a fallback. The nice thing is you don't even need enable_if, just the trailing decltype:
template <class C>
auto do_something_impl(C&& c, int)
-> decltype(std::forward<C>(c).y())
{
return std::forward<C>(c).y();
}
template <class C>
auto do_something_impl(C&& c, ...)
-> decltype(y(std::forward<C>(c))
{
return y(std::forward<C>(c));
}
And now just pass in 0:
template <class C>
auto do_something(C&& c)
-> decltype(do_something_impl(std::forward<C>(c), 0))
{
return do_something_impl(std::forward<C>(c), 0);
}
The conversion sequence to int is better than the one to ..., so if the type has the member function you want, that overload will be preferred even if both are viable candidates.

Related

What are the syntax and semantics of C++ templated code?

template<typename T, size_t M, size_t K, size_t N, typename std::enable_if_t<std::is_floating_point<T>::value, T> = 0>
void fastor2d(){//...}
I copied this line of code from cpp-reference(only the std::enable_if part, i do need T and all three of the size_t's), because i would like to use this function only when floating_types are used on it ... it does not compile.
Could somebody explain to me, why, and what it even does? While i am at it, how do you call this function afterwards?
Every tutorial or question here on SO gets bombed with answers, and that is great, but to someone who does not understand jacks*** of what is happening, even those are not really helpful.(sry, if possibly slightly agitated or aggressive)
EDIT: i greatly appreciate all answers as of now, i realize that my wording might have been a bit off ... i understand what a template parameter is, and know the difference between runtime and compiletime etc, but i just cant get a good grasp of the syntax behind std::enable_if
EDIT2:
template<typename T, size_t M, size_t K, size_t N, typename = std::enable_if_t<std::is_integral<T>::value>>
void fastor2d(){
Fastor::Tensor<T,M,K> A; A.randInt();
}
This is literally the only thing i need changed. Notice the random() part
template<typename T, size_t M, size_t K, size_t N, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void fastor2d(){
Fastor::Tensor<T,M,K> A; A.random();
}
I'll try to explain this as simple as possible not to go into the language details too much since you asked for it.
Template arguments are compile time arguments (they do not change during the run-time of your application). Function arguments are run-time and have a memory address.
Calling this function would look something like this:
fastor2d<Object, 1, 2, 3>();
In the <> brackets you see the compile-time arguments or more accurately the template parameters, and the function in this case takes 0 runtime arguments in the () brackets. The last compile time argument has a default argument which is used to check whether the function should compile at all (enable_if type). If you want to know more clearly what enable if does you should search for the term SFINAE, which is a template metaprogramming technique used to determine whether a function or class should exist or not.
Here is a short SFINAE example:
template<typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void function(T arg)
{
}
function(0.3f); //OK
function(0.0); //OK double results in std::is_floating_point<double>::value == true
function("Hello"); //Does not exist (T is not floating point)
The reason the third function call fails, is because the function does not exist. This is because the enable if caused the function not to exist when the compile-time bool that is passed in as its' template argument is false.
std::is_floating_point<std::string>::value == false
Do note that a lot of people agree that the SFINAE syntax is horrible and that a lot of SFINAE code will not be necessary anymore with the introduction of concepts and constraints in C++ 20.
Rather than a top-down approach starting with you code snippet, I'll take a bottom-up approach to explain some important details about templates and what tools and techniques are involved.
At heart, templates are a tool that let you write C++ code that applies to a range of possible types, not strictly for a fixed type. In a statically-typed language, this is firstly a great tool for reusing code without sacrificing type safety, but in C++ in particular, templates are very powerful because they can be specialized.
Every template declaration begins with the keyword template, and a list of type or non-type (i.e value) parameters. Type parameters use the special keyword typename or class, and are used to let your code work over a range of types. Non-type parameters simply use the name of an existing type, and these let you apply your code to a range of values that are known at compile-time.
A very basic templated function might look like the following:
template<typename T> // declare a template accepting a single type T
void print(T t){ // print accepts a T and returns void
std::cout << t; // we can't know what this means until the point where T is known
}
This lets us reuse code safely for a range of possible types, and we can use it as follows:
int i = 3;
double d = 3.14159;
std::string s = "Hello, world!";
print<int>(i);
print<double>(d);
print<std::string>(s);
The compiler is even smart enough to deduce the template parameter T for each of these, so you can safely get away with the following, functionally identical code:
print(i);
print(d);
print(s);
But suppose you want print to behave differently for one type. Suppose, for example, you have a custom Point2D class that needs special handling. You can do this with a template specialization:
template<> // this begins a (full) template specialization
void print<Point2D>(Point2D p){ // we are specializing the existing template print with T=Point2D
std::cout << '(' << p.x << ',' << p.y << ')';
}
Now, anytime we use print with T=Point2D, the specialization is chosen. This is really useful, for example, if the generic template just doesn't make sense for one specific type.
std::string s = "hello";
Point2D p {0.5, 2.7};
print(s); // > hello
print(p); // > (0.5,2.7)
But what if we want to specialize a template for many types at once, based on a simple condition? This is where things become a little meta. First, let's try to express a condition in a way that lets them be used inside templates. This can be a little tricky because we need compile-time answers.
The condition here will be that T is a floating point number, which is true if T=float or T=double and false otherwise. This is actually fairly simple to achieve with template specialization alone.
// the default implementation of is_floating_point<T> has a static member that is always false
template<typename T>
struct is_floating_point {
static constexpr bool value = false;
};
// the specialization is_floating_point<float> has a static member that is always true
template<>
struct is_floating_point<float> {
static constexpr bool value = true;
};
// the specialization is_floating_point<double> has a static member that is always true
template<>
struct is_floating_point<double> {
static constexpr bool value = true;
}
Now, we can query any type to see if it's a floating point number:
is_floating_point<std::string>::value == false;
is_floating_point<int>::value == false;
is_floating_point<float>::value == true;
is_floating_point<double>::value == true;
But how can we use this compile-time condition inside another template? How can we tell the compiler which template to choose when there are many possible template specializations to choose from?
This is achieved by taking advantage of a C++ rule called SFINAE, which in basic English, says, "when there are many possible template specializations to choose from, and the current one doesn't make sense*, just skip it and try the next one."
There's a list of errors, when attempting to substitute template arguments into templated code, that cause the template to be ignored without an immediate compiler error. The list is a bit long and complex.
One possible way that a template doesn't make sense is if it tries to use a type that doesn't exist.
template<typename T>
void foo(typename T::nested_type x); // SFINAE error if T does not contain nested_type
This is the exact same trick that std::enable_if uses under the hood. enable_if is a template class accepting a type T and a bool condition, and it contains a nested type type equal to T only when the condition is true. This is also pretty easy to achieve:
template<bool condition, typename T>
struct enable_if {
// no nested type!
};
template<typename T> // partial specialization for condition=true but any T
struct enable_if<true, T> {
typedef T type; // only exists when condition=true
};
Now we have a helper that we can use in place of any type. If the condition we pass is true, then we can safely use the nested type. If the condition we pass is false, then the template is no longer considered.
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type // This is the return type!
numberFunction(T t){
std::cout << "T is a floating point";
}
template<typename T>
typename std::enable_if<!std::is_floating_point<T>::value, void>::type
numberFunction(T t){
std::cout << "T is not a floating point";
}
I completely agree that std::enable_if<std::is_floating_point<T>::value, void>::type is a messy way to spell out a type. You can read it as "void if T is floating point, and otherwise stop and try the next overload"
Finally, to take apart your example:
// we are declaring a template
template<
typename T, // that accepts some type T,
size_t M, // a size_t M,
size_t K, // a size_t K,
size_t N, // a size_t N,
// and an unnamed non-type that only makes sense when T is a floating point
typename std::enable_if_t<std::is_floating_point<T>::value, T> = 0
>
void fastor2d(){//...}
Note the = 0 at the end. That's simply a default value for the final template parameter, and it lets you get away with specifying T, M, K, and N but not the fifth parameter. The enable_if used here means that you can provide other templates called fastor2d, with their own sets of conditions.
First of all, I'll rewrite your function in a working form
template <typename T, size_t M, size_t K, size_t N,
std::enable_if_t<std::is_floating_point<T>::value, int> = 0>
void fastor2d() // ..........................................^^^ int, not T
{ }
The point is that I've changed the second template argument of std::enable_if_t form T to int.
I've also removed the typename before std::enable_if_t but isn't important: the typename is implicit in the _t at the end of std::enable_if_t, introduced from C++14. In C++11 the correct form is
// C++11 version
typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0
// ^^^^^^^^ no _t ^^^^^^
But why it works?
Start from the name: SFINAE.
Is a short form for "Substitution Failure Is Not An Error".
It's a C++ rule so that when you write some thing as
template <int I, std::enable_if_t< I == 3, int> = 0>
void foo ()
{ }
and I is 3, the condition of std::enable_if_t is true so std::enable_if_t< I == 3, int> is substituted with int so foo() is enabled but when I isn't 3, the condition of std::enable_if_t if false so std::enable_if_t< I == 3, int> is not substituted so foo() isn't enabled but this ins't an error (if, through overloading, there is another foo() function, enabled, that matches the call, obviously).
So where is the problem in your code?
The problem is that std::enable_if_t is substituted, when the first template parameter is true, with the second parameter.
So if you write
std::enable_if_t<std::is_floating_point<T>::value, T> = 0
and you call
fastor2d<float, 0u, 1u, 2u>();
the std::is_floating_point<float>::value (but you can also use the shorter form std::is_floating_point_v<T> (_v and not ::value)) so the substitution take place and you get
float = 0
but, unfortunately, a template value (not type) parameter can't be of type floating point, so you get an error.
If you use int instead of T, the substitution give you
int = 0
and this is correct.
Another solution can be use the following form
typename = std::enable_if_t<std::is_floating_point<T>::value, T>
as suggested by Andreas Loanjoe, because the substitution give you
typename = float
that is a valid syntax.
But this solution has the drawback that doesn't works when you want to write two alternative functions, as in the following example
// the following solution doesn't works
template <typename T,
typename = std::enable_if_t<true == std::is_floating_point<T>::value, int>>
void foo ()
{ }
template <typename T,
typename = std::enable_if_t<false == std::is_floating_point<T>::value, int>>
void foo ()
{ }
where works the solution based on the value
// the following works
template <typename T,
std::enable_if_t<true == std::is_floating_point<T>::value, int> = 0>
void foo ()
{ }
template <typename T,
std::enable_if_t<false == std::is_floating_point<T>::value, int> = 0>
void foo ()
{ }

Get forwarded type from the template type and not the argument

Consider the following function:
template <class T>
constexpr /* something */ f(T&& x) {
// do something
}
and let's say that I want to do sfinae based on the type of a forwarded argument passed to a function called myfunction. One way to achieve this is:
template <class T>
constexpr auto f(T&& x) -> decltype(myfunction(std::forward<T>(x))) {
// do something
}
instead of doing this, is there a way to do it at the template level:
// This code won't compile
template <class T, class R = decltype(myfunction(std::forward<T>(x)))>
constexpr R f(T&& x) {
// do something
}
except that I don't have access to x yet so this code won't compile. Is there a way to achieve this only based on T (possibly using std::declval)?
Note: this is not an X/Y problem, it's just an example to illustrate where this situation happen: I don't know how to do SFINAE with forwarding without accessing the variable because for me the behavior of std::forward is still a little mysterious.
Yes, std::declval is indeed the key:
template <class T, class R = decltype(myfunction(std::declval<T>()))>
constexpr R f(T&& x) {
// do something
}
This will either SFINAE out or R will be the return type of whichever overload of myfunction is chosen.
Your question makes it appear to me that you need a refresher on how reference-collapsing works; I suggest reading up in that area (this seems like a good starting point).
std::forward() has nothing to do with this question. Nor does constexpr. So let's start out with the super basic, a function that just returns its argument by value:
template <class T>
auto f(T x) -> decltype(x);
Sure, we could just use T, but that's too easy. Now the question, how do we lift that into a template parameter while still maintaining SFINAE (granted there's obviously no possible substitution failure here, but bear with me):
template <class T, class R = decltype(x)>
R f(T x);
So that doesn't work because there's no x yet (or worse, there's some unrelated x somewhere else that name lookup finds). We can use the argument names in a trailing-return-type because they're in scope, but we cannot use them as part of expression-SFINAE in default template arguments because they're not yet in scope.
But because these are template parameters, we don't care about their values. We just care about their types. This isn't an evaluated expression. So I don't need x, I need something that has the same type as x. A first go might be:
template <class T, class R = decltype(T{})>
R f(T x);
This works... as long as T is default-constructible. But I'm writing a template, I don't want to be making assumptions on types that I don't need to be making. So instead, I can do something like:
template <class T> T make(); // never defined
template <class T, class R = decltype(make<T>())>
R f(T x);
And now we have our arbitrary expression of type T, that we can use in decltype, in a default template argument. Although, we're still a little limited with make() - there are types that you can't return by value from a functon (e.g. arrays), so it turns out to be more useful to add references. And we need a less-likely-to-collide name than make:
template <class T>
add_rvalue_reference<T> declval();
template <class T, class R = decltype(declval<T>())>
R f(T x);
This is precisely the point of std::declval<T> - to give you an expression of type T in an unevaluated context.
Back to your original problem. We use the same thought process of how to get from decltype(x) to decltype(declval<T>()), but just apply it to a different expression. Instead of x, we have myfunction(std::forward<T>(x)). Which is to say, we're invoking myfunction with the same type as our argument:
template <class T, class R = decltype(myfunction(std::declval<T&&>()))>
R f(T&& x);
But due to reference collapsing rules, std::declval<T&&> is actually the same function as std::declval<T>, so we can just write:
template <class T, class R = decltype(myfunction(std::declval<T>()))>
R f(T&& x);

Ambiguous call to variadic template function

I'm creating some classes which represent the functions in the mathematical meaning and their interface is to be 'math-friendly'. To accomplish this I want to create a variadic template operator() methods, which allow user to write defining functions in this way f(x, y) = 2*x + y; and then getting its value by calling f(4, 5);. I cannot predict the number of parameters (the number of variables in mathematical function) so I decided to use variadic templates. However overloading operator() twice as a variadic template and calling it causes the "ambigous call" error. Is there some way to overcome it, or do I have to create two seprate methods?
//expressions like f(x, y, z) = x*x+y-z
template <typename... Args>
RichFunction<T> &operator()(Args&&... args)
{
mMainLinears.clear();
setMainLinears(args...);
return *this;
}
//expressions like f(5, 4, 3)
template <typename... Args>
T operator()(Args&&... args)
{
Function<T>::assign(mMainLinears, 0, args...);
return Function<T>::value();
}
Edit: The whole background isn't very important. I only need to know how to overload variadic template method, where overloaded versions differ from each other only with arguments type.
Based on your description, I guess you need lambda expression more than variadic templates. For illustration:
auto f = [](double x, double y) { return 2 * x + y; };
std::cout << f(4, 5) << '\n';
You can SFINAE out one of the overloads if it does not meet whatever pre-requistes you want.
If I understand you correctly, the first operator() should define your mathematical expression and the second one should evaluate this expression defined previously.
To answer your question: you can not overload the method operator() in this way, since the signature in both methods is the same, i.e. exactly the same template definition and argumentlist. How should the compiler know which method to call? There must be a way to distinguish both calls.
Suggestions (1) for a solution
Probably you variable (x,y,z) are of some type. You could use the CRTP-pattern to define a common base class
template <class Sub>
struct Variable {};
struct X : Variable<X> {};
struct Y : Variable<Y> {}; //...
And then you could do an overload based on this class structure:
template <class... Xs>
ReturnType operator()(Variable<Xs>&&... vars) {...}
Inside of this method you can cast to the concrete variable type, e.g. by using static_cast<X&>(var) for a concrete argument of type Variable<X>& var.
Suggestion (2)
Use enable_if and disable_if (from boost, or std) to distinguish between the two argument types passed to the method, i.e.
template <class... Ts>
typename enable_if< is_scalar<Ts...>, ReturnType>::type
operator()(Ts&&... values) { ... }
template <class... Ts>
typename disable_if< is_scalar<Ts...>, ReturnType>::type
operator()(Ts&&... vars) { ... }
where is_scalar must be any meta-method that accepts variadic templates and defines a static boolean member value in the case that all types are scalars (number).
To the best of my knowledge, there is still no way to disambiguate methods by return value (you can disambiguate by template parameters though). You might wanna put the method to create a function into a separate object from the one that calls it if you want to keep the syntax.

Promotion of C++ overloaded function pointer to a function object

A C++11 template function which takes a function object argument, such as:
template <typename F, typename T>
auto foo(F f, T x) -> decltype(f(x)) {
return f(x);
}
could take a function such as:
int succ(int i) { return i+1; }
and apply foo to succ and obtain a result of 10:
foo(succ,9);
Overloaded functions don't work, sin, for example, fails:
foo(std::sin,0.5);
in GCC (4.7) with "couldn't deduce template parameter F".
(Providing sin<double> relates only to complex types btw.) Yes, I can struct it right up:
template <typename T>
struct Sin {
T operator()(T x) { return std::sin(x); }
};
with a little:
foo(Sin<double>(),0.5);
My question is, is there an alternative which avoids the need for such a new definition; usable solely at the call site of foo?
For function pointers, you can simply have the user type the signature:
template<class F, class T>
void foo(F f, T x){
f(x);
}
void bar(int){}
void bar(double){}
int main(){
foo<void(int)>(bar, 5);
}
Live example on Ideone.
foo will be void foo(void f(int), int x) after substitution, which is the same as foo(void (*f)(int), int x). This provides a so-called "calling context" which allows the compiler to select the correct overload. Obviously, this only works well if the first template parameter is the function. To work around this limitation, and make it look nicer (imho, atleast), you can provide a simple helper function:
template<class F>
auto get_overload(F f) -> decltype(f) { return f; }
Actually, you can only overload on parameter types, but this you can't cull out the need to have the user type the return type, since this disables the calling context again, as a type would need to be deduced.
Since you most likely (or surely) only want this for function pointers, you can change it to this:
template<class F>
F* get_overload(F* f){ return f; }
It's still completely the same. The only reason why the first version can't just have F as the return type is that F is void(int) if you call it with get_overload<void(int)>(bar), and the standard doesn't allow you to return functions (yes, that's a function type). The function to function pointer transformation (void(int) -> void(*)(int)) part only happens for parameters.
Since for whatever reason #VJovic deleted his answer, I'll just edit this in:
You can actually use a simple lambda instead of the get_overload function. It will be about the same length character wise and much more convenient and clearer. It will also be more efficient, since no (function) pointers are involved and the compiler is perfectly able to inline the call.
foo([](int i){ return bar(i); }, 5);

Handling of references in C++ templates

I currently have a function template, taking a reference, that does something in essence equivalent to:
template <typename T>
void f(T& t)
{
t = T();
}
Now, I can call:
int a;
f(a);
To initialize my variable a.
I can even do:
std::vector<int> a(10);
f(a[5]);
However, this will fail:
std::vector<bool> a(10);
f(a[5]);
The reason being a[5] returns an object with reference semantic, but not a reference. So I need to be able to write:
template <typename T>
void f(T a)
{
a = T();
}
But if I add this new template and try to compile the first example (with int), I obtain the following error:
test_multi_tmpl.cc: In function ‘int main()’:
test_multi_tmpl.cc:20: error: call of overloaded ‘f(int&)’ is ambiguous
test_multi_tmpl.cc:6: note: candidates are: void f(T&) [with T = int]
test_multi_tmpl.cc:12: note: void f(T) [with T = int]
Any ideas how to solve this? I wouldn't like to overload f just for std::vector<bool>::reference as this construct might appears in other places ...
I think specialising f for std::vector<bool>::reference is your only option.
Note that using std::vector<bool> is probably a bad idea in the first place (the std::vector<bool> specialisation is deprecated for future versions of the c++ language) so you could just use std::deque<bool> instead.
I'm not sure whether you already know about this...
The specialization std::vector is not really a STL container because it does not meet the necessary requirements. In particular, it's not possible to created proxied containers that satisfy the STL concepts because of the reference semantics (you can't fake a reference). Check this article for more information. (Also, as Autopulated mentioned there should be a compiler directive to provide control over std::vector in the future C++ Standard.)
A simple workaround that could solve your problem is by overloading function f for this particular type (and others if they appear and are not many). Notice that this is an overload and not an specialization. You might also wanna check this for why not specialize function templates.
void f(std::vector<bool>::reference t)
{
/* ... */
}
There are two ways to do this, one is, as you suggest, specialize for std::vector<bool>::reference. The other is by using type-traits dispatching.
template <class T>
void f (T& t) {
f_impl(t, is_reference_wrapper_type<T>());
}
template <class T>
void f_impl(T& t, mpi::false_) {
t = T();
}
template <class T>
void f_impl(T& t, mpi::true_) {
// do nothing, or voodoo here
}
Note the code above is un-tested and there would be more complex means of dispatching based on a trait -- or a set of traits -- in this situation.
This would also mean that you would need to implement is_reference_wrapper_type like so:
template <class T>
struct is_reference_wrapper_type : mpi::false_ {};
template <>
struct is_reference_wrapper_type<std::vector<bool>::reference> : mpi::true_ {};
Using traits or template specialization would make it work.