Approaches to function SFINAE in C++ - c++

I am using function SFINAE heavily in a project and am not sure if there are any differences between the following two approaches (other than style):
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
The program output is as expected:
method 1
method 2
Done...
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Are there any circumstances when these two approaches differ?

I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Suggestion: prefer method 2.
Both methods work with single functions. The problem arises when you have more than a function, with the same signature, and you want enable only one function of the set.
Suppose that you want enable foo(), version 1, when bar<T>() (pretend it's a constexpr function) is true, and foo(), version 2, when bar<T>() is false.
With
template <typename T, typename = std::enable_if_t<true == bar<T>()>>
void foo () // version 1
{ }
template <typename T, typename = std::enable_if_t<false == bar<T>()>>
void foo () // version 2
{ }
you get a compilation error because you have an ambiguity: two foo() functions with the same signature (a default template parameter doesn't change the signature).
But the following solution
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true>
void foo () // version 1
{ }
template <typename T, std::enable_if_t<false == bar<T>(), bool> = true>
void foo () // version 2
{ }
works, because SFINAE modify the signature of the functions.
Unrelated observation: there is also a third method: enable/disable the return type (except for class/struct constructors, obviously)
template <typename T>
std::enable_if_t<true == bar<T>()> foo () // version 1
{ }
template <typename T>
std::enable_if_t<false == bar<T>()> foo () // version 2
{ }
As method 2, method 3 is compatible with selection of alternative functions with same signature.

In addition to max66's answer, another reason to prefer method 2 is that with method 1, you can (accidentally) pass an explicit type parameter as the second template argument and defeat the SFINAE mechanism completely. This could happen as a typo, copy/paste error, or as an oversight in a larger template mechanism.
#include <cstdlib>
#include <type_traits>
#include <iostream>
// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
std::cout << "method 1" << std::endl;
}
int main(){
// works fine
foo<int>();
// ERROR: subsitution failure, as expected
// foo<double>();
// Oops! also works, even though T != int :(
foo<double, double>();
return 0;
}
Live demo here

Related

How to get a forwarding function to call a base template function that is declared after the forwarding function

I have a case where I need to have a forwarding function defined before a template base function is defined/declared. However, if I call the forwarding function (fwd) that in turn calls the base function test, it says that the base template function is not visible (see the code below). However, if test is called directly, everything works.
So my question is this, is it possible to have the forwarding function make a call to a base template function that is defined later in the compilation unit (before it is used but after the forwarding function)? If not, do I have any options to work around this? I would like to avoid a forward declaration before fwd as that would make use of the library I am developing harder. I think if I could force fwd to be inline it would solve the problem but I have no way of doing that unless a macro is used.
#include <iostream>
#include <vector>
template<typename T, std::enable_if_t<std::is_scalar<T>::value, int> = 0>
void test(const T& t)
{
std::cout << "Scalar" << std::endl;
}
template<typename T>
void fwd(T&& t)
{
test(std::forward<T>(t));
}
template<typename T>
void test(const std::vector<std::vector<T>>& t)
{
std::cout << "vector vector of T" << std::endl;
}
int main(int argc, const char * argv[]) {
test(1); //OK, prints Scalar
fwd(1); //OK, prints Scalar
test(std::vector<std::vector<int>>()); //OK, prints vector vector of T
// Causes compile error: Call to function 'test' that is neither visible in the template definition
// nor found by argument dependent lookup
fwd(std::vector<std::vector<int>>());
return 0;
}
The name test in fwd is a dependent name. It will be resolved into two steps:
Non-ADL lookup examines function declarations ... that are visible from the template definition context.
ADL examines function declarations ... that are visible from either the template definition context or the template instantiation context.
Given that the relative order of test and fwd should not be changed, one possible solution is to use a fake tag struct in the namespace to activate ADL:
namespace my_namespace
{
struct Tag {};
template<typename T, std::enable_if_t<std::is_scalar<T>::value, int> = 0>
void test(const T& t, Tag = Tag{}) {
std::cout << "Scalar" << std::endl;
}
template<typename T>
void fwd(T&& t) {
test(std::forward<T>(t), Tag{});
}
template<typename T>
void test(const std::vector<std::vector<T>>& t, Tag = Tag{}) {
std::cout << "vector vector of T" << std::endl;
}
}
int main() {
my_namespace::test(std::vector<std::vector<int>>()); // OK
my_namespace::fwd(std::vector<std::vector<int>>()); // OK, too
}
Demo
Depending on what test overloads you have, another solution might be to wrap these functions into structs and use template specialization instead of function overloading:
template<class T>
struct Test {
static void op(const T& t) {
std::cout << "Scalar" << std::endl;
}
};
template<typename T>
void fwd(T&& t) {
Test<std::decay_t<T>>::op(std::forward<T>(t));
}
template<class T>
struct Test<std::vector<std::vector<T>>> {
static void op(const std::vector<std::vector<T>>& t) {
std::cout << "vector vector of T" << std::endl;
}
};
int main() {
fwd(1);
fwd(std::vector<std::vector<int>>());
}
Demo

Template specialization with enable_if fails in Clang, works with GCC

I am trying to remove a member function based on the template type. The problem is to make a later template specialization match the type signature of my function in a case when it is not removed.
I tried the following code, which compiles with GCC (9.0.1) but gives an error in Clang (9.0.0). I think it also fails to build the code in MSVC++.
#include <type_traits>
#include <iostream>
template <typename T>
struct my_type {
template <typename Q = T>
std::enable_if_t<!std::is_same<bool, Q>::value, my_type<T>> my_fun(const my_type<T>& v) {
std::cout << "Base";
return v;
}
};
template <>
template <typename Q>
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>> my_type<double>::my_fun(const my_type<double>& v) {
std::cout << "Specialized";
return v;
}
int main()
{
my_type<double> aa, bb;
aa.my_fun(bb);
}
The error with Clang is
prog.cc:16:88: error: out-of-line definition of 'my_fun' does not match any declaration in 'my_type<double>'
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>> my_type<double>::my_fun(const my_type<double>& v) {
^~~~~~
1 error generated.
I would like to know how to make the code work, and also why the results are not consistent cross all the major compilers.
In both cases: my_type is specialised to double. Then compare non-specialised version of my_fun
template < >
template <typename Q>
std::enable_if_t<!std::is_same_v<bool, Q>::value, my_type<double>>
// ^ (!)
my_type<double>::my_fun(const my_type<double>& v)
against the fully specialised my_fun:
template < >
template < >
// ^
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>>
my_type<double>::my_fun<double>(const my_type<double>& v)
// ^
Both of above variants would be legal; you, in contrast, ended up somewhere in between...
GCC accepting this code doesn't look right to me, I join the 'this is a bug' fraction in the comments.
Perhaps even worse: Consider my_type<double>::my_fun<bool> specialisation – it should still exist, shouldn't it?
I don't know how to make this work with specialization. But I do know how to just side-step the issue entirely:
template <typename> struct tag { };
template <typename Q = T>
std::enable_if_t<!std::is_same_v<bool, Q>, my_type<T>> my_fun(const my_type<T>& v) {
return my_fun_impl(v, tag<Q>{});
}
with:
template <typename U>
my_type my_fun_impl(const my_type& v, tag<U>) {
std::cout << "Base";
return v;
}
my_type my_fun_impl(const my_type& v, tag<double>) {
std::cout << "Specialized";
return v;
}
If you wanted specialization to give users the ability to add specialized implementations, you could make my_fun_impl a free function instead of a member function. If the goal was just to specialize for certain types, you can make them private member functions.
You cannot use enable_if here to suppress a member function depending on the template parameter of the class, i.e. T (but only depending on the template parameter of the function, i.e. Q.
Your code is wrong, as clang rightly points out. I don't know why gcc accepts it and how it can detect what Q is in your 'specialisation' (I reckon your code compiled with gcc stated "Base" -- correct? Also as there is no inheritance, it's not clear why you use "Base".)
W/o tag type, you could do the following.
template <typename T>
struct my_type {
private:
template<bool Standard>
std::enable_if_t<Base, my_type> my_fun_impl(const my_type& v)
{
std::cout << "Standard";
return v;
}
template<bool Standard>
std::enable_if_t<!Standard, my_type> my_fun_impl(const my_type& v)
{
std::cout << "Specialised";
return v;
}
public:
my_type my_fun(const my_type& v)
{
return my_fun_impl<is_standard<T>::value>(v);
}
};
for whatever is_standard<> you want.

Are all lambdas inside templated lambdas also templated lambdas?

Consider this code (which compiles on GCC and MSVC):
int main()
{
auto foo = [](auto p){
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar();
};
std::cout << foo(0ull) << std::endl;
}
foo() is a templated lambda because it has an auto parameter. But for bar() to know the type p_t, it must somehow be implicitly templated too, which then leads me to the question in the title:
Are all lambdas inside templated lambdas also templated lambdas?
If that's the case, then it seems like the number of templates parameters will grow pretty quickly if I have lots of nested lambdas (not necessarily a bad thing, but it comes as a surprise to me).
I'm not sure if you can actually say that a lambda is templated. The type of lambda with auto template parameter is not a template at all in the sense it does not match to template template parameter:
#include <iostream>
auto foo = [](auto param){};
template <class T>
struct functor_template {
void operator()() const { }
};
template <template <class...> class Foo, class... Ts>
void bar(Foo<Ts...>) {
}
int main() {
//bar(foo); //prog.cc:7:6: note: template argument deduction/substitution failed
bar(functor_template<int>{});
}
The reason for that is quite simple - only thing that is very close to be called template in such lambdas is their operator().
But I think you wanted to ask more if the type of lambda inside the lambda with auto parameter(s) is depended on parameters' types passed to that lambda. The answer is - yes. This can be easily tested:
#include <iostream>
#include <type_traits>
auto foo = [](auto p){
static_cast<void>(p);
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar;
};
int main() {
static_cast<void>(foo);
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(float{}))>::value << std::endl;
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(int{}))>::value << std::endl;
}
Output:
0
1

Template argument deduction (using both explicit and implicit arguments in same call)

I have three template arguments to a function and am having troubles with (I think) the compiler deducing which template argument is which.
The template function is:
#include <structures/partition.h>
#include <vector>
namespace cliques
{
template <typename P, typename T, typename QF>
P find_optimal_partition_louvain(cliques::Graph<T> &my_graph,
QF quality_function)
{
P dummy;
}
}
And when I try to call it with
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Where template argument P should correspond to cliques::DisjointSetForest, and the normal function arguments are a templated class and a function object.
This fails with
error: no matching function for call to
find_optimal_partition_louvain(cliques::Graph<lemon::ListGraph>&,
cliques::find_linearised_stability)
However if I use a builtin type such as an int or a float for the P parameter everything compiles fine.
e.g.
cliques::find_optimal_partition_louvain<int>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
So my question is what am I doing wrong here, how can I use a better inform the compiler which parameter is which, or am I completely off track?
I hate to answer my own question but problem was that cliques::DisjointSubsetForest is actually a templated class so
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest<int> >(my_new_graph, cliques::find_linearised_stability(current_markov_time));
works
"error: no matching function for call to ‘find_optimal_partition_louvain(cliques::Graph&, cliques::find_linearised_stability)"
It would seem that your compiler thinks that cliques::Graph is not a template.
I have tried to reproduce the error on a simple example, but I failed to do so (on gcc).
It looks as though the compiler does figure out that find_optimal_partition_louvain is a function template. I suggest trying the following:
cliques::template find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Otherwise, you might want to verify if the following simple example compiles fine on your compiler (because it should!):
#include <iostream>
template <class G>
struct Bar { };
namespace Foo {
template <class A, class B, class C>
A some_function(Bar<B>&, C aFunc) {
aFunc();
return A();
};
};
struct HWPrinter {
HWPrinter() { std::cout << "Hello World!" << std::endl; };
};
struct IntPrinter {
int value;
IntPrinter(int aValue) : value(aValue) { };
void operator() () { std::cout << "The integer is: " << value << std::endl; };
};
int main() {
Bar<HWPrinter> ab;
Foo::some_function<HWPrinter>(ab,IntPrinter(42));
return 0;
};

Checking if a function with a given signature exists in c++

So I was looking for ways to check whether a function with a particular argument exists. I have a templated method which relies on an external function (external from the class) to do the job:
template <class Moo>
void exportDataTo(Moo& ret){
extended_solid_loader(ret, *this);
}
At multiple points in the project I have macros which define extended_solid_loader for different types, but now I want to be able to use a default function if extended_solid_loader hasn't been defined for that particular class type.
I came across this:
Is it possible to write a template to check for a function's existence?
but it seems a little different, in that I'm not checking for a method, but rather a definition of a function with a particular argument type.
Is this possible right now?
You can just provide a function template for extended_solid_loader providing a default implementation, and users who want to use something other than the default implementation just specialize that.
template<class T>
void extended_solid_loader(T & ret, SomeClass & obj) {
// default implementation here
}
template<>
void extended_solid_loader<MooClass>(MooClass & ret, SomeClass & obj) {
// special implementation for MooClass here
}
You don't actually have to do anything particularly special. Just make sure there's a version of that function available to the template and let ADL do the dirty work. Check out this example:
#include <iostream>
namespace bob {
struct X {};
void f(X const&) { std::cout << "bob::f\n"; }
}
namespace ed {
template < typename T >
void f(T const&) { std::cout << "ed::f\n"; }
template < typename T >
struct test
{
void doit() // not called f and no other member so named.
{ f(T()); }
};
}
int main()
{
ed::test<int> test1;
ed::test<bob::X> test2;
test1.doit();
test2.doit();
std::cin.get();
}
Works without the namespace stuff too (non-templates have preference). I just used that to show that ADL will pick it up when you do.
Your original question was interesting. Found a way to do it in C++0x:
template < typename T >
struct fun_exists
{
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename U >
static yes check(decltype(f(U()))*);
template < typename U >
static no check(...);
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
void f(double const&) {}
struct test {};
#include <iostream>
int main()
{
std::cout << fun_exists<double>::value << std::endl;
std::cout << fun_exists<test>::value << std::endl;
std::cin.get();
}