Why Can't These Templatized Functions Take No Arguments? - c++

I am trying to use a couple templatized functions for Substitution Fail Is Not An Error(SFINAE). And I can do it like this:
template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(R*);
template<typename R> static false_type Test(...);
But I'm not understanding how the argument makes this SNFIAE work. It seems like I should just be able to remove the arguments and the template selection would work the exact same way:
template<typename R, typename S = decltype(declval<R>().test())> static true_type Test();
template<typename R> static false_type Test();
But it does not, I get:
Call of overloaded 'Test()' is ambiguous
What is it about these arguments that make this SFINAE work?

Your second example fails to compile, since there are two overloads of Test with identical signature, becasue defaulted template type arguments are not part of function signature. That is not allowed.
Your first example works in followign manner:
When type R does have a function test in it, both Test become valid overload candidates. However, ellipsis functions have lower rank than non-ellipsis ones, and thus compiler selects the first overload, returning true_type.
When R does not have test on it, the first overload is excluded from overload resolution set (SFINAE at works). You are left with only the second one, which returns false_type.

The question has been answered but maybe it's useful to go into a deeper explanation.
Hopefully this annotated program will make things clearer:
#include <utility>
#include <iostream>
// define the template function Test<R> if and only if the expression
// std::declval<R>().test()
// is a valid expression.
// in which case Test<R, decltype(std::declval<R>().test())>(0) will be preferrable to... (see after)
template<typename R, typename S = decltype(std::declval<R>().test())>
static std::true_type Test(R*);
// ...the template function Test<R>(...)
// because any function overload with specific arguments is preferred to this
template<typename R> static std::false_type Test(...);
struct foo
{
void test();
};
struct bar
{
// no test() method
// void test();
};
// has_test<T> deduces the type that would have been returned from Test<T ... with possibly defaulted args here>(0)
// The actual Test<T>(0) will be the best candidate available
// For foo, it's Test<foo, decltype(std::declval<R>().test())>(foo*)
// which deduces to
// Test<foo, void>(foo*)
// because that's a better match than Test<foo>(...)
//
// for bar it's Test<bar>(...)
// because Test<bar, /*error deducing type*/>(bar*)
// is discarded as a candidate, due to SFNAE
//
template<class T>
constexpr bool has_test = decltype(Test<T>(0))::value;
int main()
{
std::cout << has_test<foo> << std::endl;
std::cout << has_test<bar> << std::endl;
}

Related

What does ... (ellipsis) as one and only function parameter in a function prototype mean in C++?

I´ve came across a function declaration, like:
int vsa_d(...);
with ... as one and only parameter.
I know that with an ellipsis, we can refer to multiple objects, but to what does the ... refer to here?
What does that mean and for what is it meant for?
To what ... gets evaluated by the compiler?
Could the ellipsis be used also as a function argument, at the invocation of a function?
I´ve found here https://en.cppreference.com/w/cpp/language/variadic_arguments under "Notes":
In the C programming language, at least one named parameter must appear before the ellipsis parameter, so printz(...); is not valid. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution.
So, it shall be used for anything like a "fallback overload" in "SFINAE".
What does that mean?
The ... argument is used as a catch-all in some SFINAE constructions.
Here is an except from the top answer in a question about writing a type trait has_helloworld<T> that detects whether a type T has a member helloworld:
template <typename T>
class has_helloworld
{
typedef char one;
struct two { char x[2]; };
template <typename C> static one test( typeof(&C::helloworld) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
int main(int argc, char *argv[])
{
std::cout << has_helloworld<Hello>::value << std::endl;
std::cout << has_helloworld<Generic>::value << std::endl;
return 0;
}
It works in the following way: if typeof(&T::helloworld) exists and is a well-formed, then at the site test<T>(0), the constant 0 is converted to a pointer-to-member(-function) and that overload is selected. The size of the return type is one.
If typeof(&T::helloworld) does not exist, then that overload is not in the potential overload set, and the fallback test(...) is selected as the overload. The size of the return type is two.
The test(...) overload has the nice property that it is always the worst-matching, last-selected overload. This means it can serve as the "fallback default" in such constructions.
int vsa_d(...); // can take any number of arguments
Here, vsa_d can take any number of arguments.
So, it shall be used for anything like a "fallback overload" in
"SFINAE".
What does that mean?
Example:
template <typename T>
struct has_f {
template <typename U, typename = decltype(std::declval<U&>().f())>
static std::true_type foo(U);
static std::false_type foo(...);
using type = typename decltype(foo(std::declval<T>()))::type;
};
struct a {
void f(){}
};
Here foo has two overloads:
template <typename U, typename = decltype(std::declval<U&>().f())>
static std::true_type foo(U);
If the expression decltype(std::declval<U&>().f() is valid, then whatever we called has_f with has indeed a function f and this overload will be chosen.
Otherwise, the non-template member function will be chosen
static std::false_type foo(...);
Because it has the lowest priority.
Calling
std::cout << std::boolalpha << has_f<a>::type();
gives
true

Compile time deduction of template member function

Is it possible to get the return type of a template member function at compile time?
I guess I need something along the lines of:
template<class T>
struct SomeClass
{
// T must have a function foo(int), but do not know the
// return type, it could be anything
using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}
What you want to do can be achieved by using the decltype operator together with the std::declval template.
decltype(EXPRESSION) yields – at compile time – the type that EXPRESSION would have. The EXPRESSION itself is never evaluated. This is much like sizeof(EXPRESSION) returns the size of whatever EXPRESSION evaluates to without ever actually evaluating it.
There is only one problem: Your foo is a non-static member function so writing decltype(T::foo(1)) is an error. We somehow need to obtain an instance of T. Even if we know nothing about its constructor, we can use std::declval to obtain a reference to an instance of it. This is a purely compile-time thing. std::declval is actually never defined (only declared) so don't attempt to evaluate it at run-time.
Here is how it would look together.
#include <type_traits>
template <typename SomeT>
struct Something
{
using RetT = decltype(std::declval<SomeT>().foo(1));
};
To see that it actually works, consider this example.
struct Bar
{
float
foo(int);
};
struct Baz
{
void
foo(int);
};
int
main()
{
static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}
While this does what I think you have asked for, it is not ideal in the sense that if you attempt to instantiate Something<T> with a T that doesn't have an appropriate foo member, you'll get a hard compiler error. It would be better to move the type computation into the template arguments such that you can benefit from the SFINAE rule.
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
If you know the argument types to your function call the following should work:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
If you don't you can still deduce the type of the function pointer and extract the return type:
template<class F>
struct return_type;
template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };
template<typename T>
struct X
{
typedef typename return_type<decltype(&T::foo)>::type type;
};
This will fail if T::foo is an overloaded function or member of T.
Unfortunately it is only possible to know the return type of some expression if you know with what arguments you are going to call it (which, unfortunately, often is a different place from where you need to know the return type)...

Using SFINAE to detect a static constexpr [duplicate]

I'm working on upgrading some C++ code to take advantage of the new functionality in C++11. I have a trait class with a few functions returning fundamental types which would most of the time, but not always, return a constant expression. I would like to do different things based on whether the function is constexpr or not. I came up with the following approach:
template<typename Trait>
struct test
{
template<int Value = Trait::f()>
static std::true_type do_call(int){ return std::true_type(); }
static std::false_type do_call(...){ return std::false_type(); }
static bool call(){ return do_call(0); }
};
struct trait
{
static int f(){ return 15; }
};
struct ctrait
{
static constexpr int f(){ return 20; }
};
int main()
{
std::cout << "regular: " << test<trait>::call() << std::endl;
std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
The extra int/... parameter is there so that if both functions are available after SFINAE, the first one gets chosen by overloading resolution.
Compiling and running this with Clang 3.2 shows:
regular: 0
constexpr: 1
So this appears to work, but I would like to know if the code is legal C++11. Specially since it's my understanding that the rules for SFINAE have changed.
NOTE: I opened a question here about whether OPs code is actually valid. My rewritten example below will work in any case.
but I would like to know if the code is legal C++11
It is, although the default template argument may be considered a bit unusual. I personally like the following style better, which is similar to how you (read: I) write a trait to check for a function's existence, just using a non-type template parameter and leaving out the decltype:
#include <type_traits>
namespace detail{
template<int> struct sfinae_true : std::true_type{};
template<class T>
sfinae_true<(T::f(), 0)> check(int);
template<class>
std::false_type check(...);
} // detail::
template<class T>
struct has_constexpr_f : decltype(detail::check<T>(0)){};
Live example.
Explanation time~
Your original code works† because a default template argument's point of instantiation is the point of instantiation of its function template, meaning, in your case, in main, so it can't be substituted earlier than that.
§14.6.4.1 [temp.point] p2
If a function template [...] is called in a way which uses the definition of a default argument of that function template [...], the point of instantiation of the default argument is the point of instantiation of the function template [...].
After that, it's just usual SFINAE rules.
† Atleast I think so, it's not entirely clear in the standard.
Prompted by #marshall-clow, I put together a somewhat more-generic version of an type-trait for detecting constexpr. I modelled it on std::invoke_result, but because constexpr depends on the inputs, the template arguments are for the values passed in, rather than the types.
It's somewhat limited, as the template args can only be a limited set of types, and they're all const when they get to the method call. You can easily test a constexpr wrapper method if you need other types, or non-const lvalues for a reference parameter.
So somewhat more of an exercise and demonstration than actually-useful code.
And the use of template<auto F, auto... Args> makes it C++17-only, needing gcc 7 or clang 4. MSVC 14.10.25017 can't compile it.
namespace constexpr_traits {
namespace detail {
// Call the provided method with the provided args.
// This gives us a non-type template parameter for void-returning F.
// This wouldn't be needed if "auto = F(Args...)" was a valid template
// parameter for void-returning F.
template<auto F, auto... Args>
constexpr void* constexpr_caller() {
F(Args...);
return nullptr;
}
// Takes a parameter with elipsis conversion, so will never be selected
// when another viable overload is present
template<auto F, auto... Args>
constexpr bool is_constexpr(...) { return false; }
// Fails substitution if constexpr_caller<F, Args...>() can't be
// called in constexpr context
template<auto F, auto... Args, auto = constexpr_caller<F, Args...>()>
constexpr bool is_constexpr(int) { return true; }
}
template<auto F, auto... Args>
struct invoke_constexpr : std::bool_constant<detail::is_constexpr<F, Args...>(0)> {};
}
Live demo with use-cases on wandbox

Detecting constexpr with SFINAE

I'm working on upgrading some C++ code to take advantage of the new functionality in C++11. I have a trait class with a few functions returning fundamental types which would most of the time, but not always, return a constant expression. I would like to do different things based on whether the function is constexpr or not. I came up with the following approach:
template<typename Trait>
struct test
{
template<int Value = Trait::f()>
static std::true_type do_call(int){ return std::true_type(); }
static std::false_type do_call(...){ return std::false_type(); }
static bool call(){ return do_call(0); }
};
struct trait
{
static int f(){ return 15; }
};
struct ctrait
{
static constexpr int f(){ return 20; }
};
int main()
{
std::cout << "regular: " << test<trait>::call() << std::endl;
std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
The extra int/... parameter is there so that if both functions are available after SFINAE, the first one gets chosen by overloading resolution.
Compiling and running this with Clang 3.2 shows:
regular: 0
constexpr: 1
So this appears to work, but I would like to know if the code is legal C++11. Specially since it's my understanding that the rules for SFINAE have changed.
NOTE: I opened a question here about whether OPs code is actually valid. My rewritten example below will work in any case.
but I would like to know if the code is legal C++11
It is, although the default template argument may be considered a bit unusual. I personally like the following style better, which is similar to how you (read: I) write a trait to check for a function's existence, just using a non-type template parameter and leaving out the decltype:
#include <type_traits>
namespace detail{
template<int> struct sfinae_true : std::true_type{};
template<class T>
sfinae_true<(T::f(), 0)> check(int);
template<class>
std::false_type check(...);
} // detail::
template<class T>
struct has_constexpr_f : decltype(detail::check<T>(0)){};
Live example.
Explanation time~
Your original code works† because a default template argument's point of instantiation is the point of instantiation of its function template, meaning, in your case, in main, so it can't be substituted earlier than that.
§14.6.4.1 [temp.point] p2
If a function template [...] is called in a way which uses the definition of a default argument of that function template [...], the point of instantiation of the default argument is the point of instantiation of the function template [...].
After that, it's just usual SFINAE rules.
† Atleast I think so, it's not entirely clear in the standard.
Prompted by #marshall-clow, I put together a somewhat more-generic version of an type-trait for detecting constexpr. I modelled it on std::invoke_result, but because constexpr depends on the inputs, the template arguments are for the values passed in, rather than the types.
It's somewhat limited, as the template args can only be a limited set of types, and they're all const when they get to the method call. You can easily test a constexpr wrapper method if you need other types, or non-const lvalues for a reference parameter.
So somewhat more of an exercise and demonstration than actually-useful code.
And the use of template<auto F, auto... Args> makes it C++17-only, needing gcc 7 or clang 4. MSVC 14.10.25017 can't compile it.
namespace constexpr_traits {
namespace detail {
// Call the provided method with the provided args.
// This gives us a non-type template parameter for void-returning F.
// This wouldn't be needed if "auto = F(Args...)" was a valid template
// parameter for void-returning F.
template<auto F, auto... Args>
constexpr void* constexpr_caller() {
F(Args...);
return nullptr;
}
// Takes a parameter with elipsis conversion, so will never be selected
// when another viable overload is present
template<auto F, auto... Args>
constexpr bool is_constexpr(...) { return false; }
// Fails substitution if constexpr_caller<F, Args...>() can't be
// called in constexpr context
template<auto F, auto... Args, auto = constexpr_caller<F, Args...>()>
constexpr bool is_constexpr(int) { return true; }
}
template<auto F, auto... Args>
struct invoke_constexpr : std::bool_constant<detail::is_constexpr<F, Args...>(0)> {};
}
Live demo with use-cases on wandbox

Call function template overload for derived variadic class template

I have a variadic class template deriv which derives off variadic class template base.
I have a function template which takes any type T, and an overload for base<Ts...> types;
How can I get the base<Ts...> overload to be used when passing a const deriv<Ts...>&?
Working example below:
#include <iostream>
#include <tuple>
template<typename... Ts>
struct base
{
std::tuple<Ts...> tuple;
};
template<typename... Ts>
struct deriv : base<Ts...>
{
};
//--------------------------------
template<typename T>
void func(const T&)
{
std::cout << "T" << std::endl;
}
template<typename... Ts>
void func(const base<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
//----------------------------------------
int main()
{
int a;
base <int, double> b;
deriv<int, double> c;
func(a);
func(b);
func(c); // <--- I want func<base<Ts...>> not func<T> to be called here
exit(0);
}
Output from exemplar:
T
base<Ts...>
T
What I want the output to be:
T
base<Ts...>
base<Ts...>
Unless you are ready to re-engineer your code, you cannot, and for a good reason.
Your non-variadic overload of func() is a better match than the variadic version: in fact, when attempting to resolve your function call, the type parameter T for the non-variadic overload will be deduced to be derived<int, double>.
On the other hand, the parameter pack Ts in your variadic overload will be deduced to be int, double. After type deduction, this will practically leave the compiler with these two choices for resolving your call:
void func(const deriv<int, double>&); // Non-variadic after type deduction
void func(const base<int, double>&); // Variadic after type deduction
Which one should be picked when trying to match a call whose argument is of type derived<int, double>?
deriv<int, double> c;
func(c);
Obviously, the first, non variadic overload is a better match.
So how do you get the second overload called instead of the first? You have a few choices. First of all, you can qualify your call by explicitly specifying the template arguments:
func<int, double>(c);
If you do not like that, maybe you can re-think the definition of the non-variadic overload of func(): do you really want it to accept any possible type T? Or are there some types for which you know this overload is not to be invoked? If so, you can use SFINAE techniques and std::enable_if to rule out the undesired matches.
As a further possibility, you can relax a bit the signature of your template function and allow deducing its argument as an instantiation of a certain template class:
template<template<typename...> class T, typename... Ts>
void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
This change alone should fix your program's behavior in the way you want.
UPDATE:
If you want your specialized function template to be invoked only for classes derived from any instance of the base<> class template, you can use the std::is_base_of<> type trait and std::enable_if in the following way:
template<template<typename...> class T, typename... Ts>
void func(
const T<Ts...>&,
typename std::enable_if<
std::is_base_of<base<Ts...>, T<Ts...>>::value
>::type* = nullptr
)
{
std::cout << "base<Ts...>" << std::endl;
}
ADDENDUM:
In those situations where template function overloading won't help with your design, notice that you can always resort to partial template specialization. Unfortunately, function templates cannot be specialized, but you can still exploit class template partial specialization and add a helper function to hide the instantiation of that template. This is how you would rewrite your code:
namespace detail
{
template<typename T>
struct X
{
static void func(const T&)
{
std::cout << "T" << std::endl;
}
};
template<template<typename...> class T, typename... Ts>
struct X<T<Ts...>>
{
static void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
};
}
template<typename T>
void func(const T& t)
{
details::X<T>::func(t);
}
The generic-template overload is a better match, since it requires no conversion (except adding const, which both overloads have).
You can get the base-template overload by adding an explicit cast (example):
func(static_cast<base<int, double> &>(c));
(Alternatively, you could forgo the multiple overloads and instead stick some is_base_of helper logic into your main function template's body.)