My compiler doesn't support if constexpr, but I am captivated by its benefit.
I must have it - even it might be a fake one.
This code is my attempt to mimic if constexpr behavior.
The objective is to make the lines (###) appear in only 1 function :-
#include <iostream>
using namespace std;
template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1){
f(i1); //No! The compiler still tried to compile even Flag=true
}
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1){ }
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1,int i2){
f(i1,i2); //No! The compiler still tried to compile even Flag=false
}
template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1,int i2){}
template<bool Flag,typename F> constexpr void fff( F f ){
for(int n=0;n<5;n++){//fake loop, the real situation is very complex
//### some horror code appeared here, but omitted
if(Flag){//attempt to mimic "if constexpr"
iter_<true>(f,1,2);
}else{
iter_<false>(f,3);
}
}
}
This is its usage:-
template<typename F> constexpr void fff1( F f ){fff<false>(f);} //usage
template<typename F> constexpr void fff2( F f ){fff<true>(f);} //usage
int main() {
// your code goes here
auto f1=[&](int a){
cout<<a<<" ";
};
auto f2=[&](int a,int b){
cout<<a<<" "<<b<<endl;
};
fff1(f1);
fff2(f2);
return 0;
}
I got compile error :
prog.cpp: In instantiation of 'constexpr typename std::enable_if<Flag, void>::type iter_(F, int, int) [with bool Flag = true; F = main()::<lambda(int)>; typename std::enable_if<Flag, void>::type = void]':
prog.cpp:16:18: required from 'constexpr void fff(F) [with bool Flag = false; F = main()::<lambda(int)>]'
prog.cpp:22:61: required from 'constexpr void fff1(F) [with F = main()::<lambda(int)>]'
prog.cpp:33:9: required from here
prog.cpp:9:3: error: no match for call to '(main()::<lambda(int)>) (int&, int&)'
f(i1,i2);
^
prog.cpp:9:3: note: candidate: void (*)(int) <conversion>
prog.cpp:9:3: note: candidate expects 2 arguments, 3 provided
From the error, it is clear to me that even when a function has std::enable_if[ effective FALSE],
the compiler still compiled code that inside the function.
- That is bad.
Which parts do I have to edit?
... or are there any alternatives?
... or is it not possible to mimic if constexpr at all (that is the reason why it is introduced finally)?
Read this: http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
Can't we do this with existing language features?
John Spicer suggested in c++std-ext-17099 that polymorphic lambdas
combined with a decision-making template would provide an adequate
facility without a need to add new language features. The invocation
of that decision-making template looks roughly like this:
template <int arg, typename ... Args> int do_something(Args... args) {
return static_if<sizeof...(args)>::get(
[](auto x, auto y) { return x+y; },
[](auto x) { return *x; })(args...);
}
Now, in comparison, with the proposed language facility, we do
template <int arg, typename ... Args> int do_something(Args... args) {
constexpr if (sizeof...(args)) {
return (args + ...);
} constexpr_else {
return *args...;
}
}
Now this is sort of a an alternative. It gets more complicated if the different branches return different types.
Moreover,
I must point out some things here:
I can return, break, continue and goto from within a constexpr if
block. I can not do that from within the lambda.
While I am a big
proponent of using lambdas to create new control facilities, I find
the constexpr if solution infinitely more readable.
Further,
Richard Smith explained the following:
Right, when a function template is instantiated, all of the
declarations/statements/expressions within it are instantiated, and
that includes pieces inside local classes, generic lambdas, and so on.
This instantiation of generic lambda bodies is in fact necessary for
our language semantics -- computing the captures of a generic lambda
within a function template specialization relies on us having already
instantiated the complete closure type and its call operator template
to the point that we know where the odr-uses are within the
non-dependent full-expressions within the body.
In contrast, the intent of constexpr if is that the branch not taken
is not instantiated.
Related
I'm trying to port some code written for GCC (8.2) to be compilable by Clang:
#include <tuple>
struct Q{};
using TUP = std::tuple<Q>;
template<typename Fn>
inline
void feh(Fn&, const std::tuple<>*)
{}
template<typename Fn, typename H>
inline
void feh(Fn& fn, const std::tuple<H>*)
{
fn(H{});
}
template<typename Fn, typename H, typename... R>
inline
void feh(Fn& fn, const std::tuple<H, R...>*)
{
fn(H{});
using Rest = const std::tuple<R...>*;
feh<Fn, R...>(fn, static_cast<Rest>(nullptr));
}
template<typename Tuple, typename Fn>
inline
void fe(Fn& fn, const Tuple * tpl = nullptr)
{
feh(fn, tpl);
}
int main()
{
auto r = [] (Q const&) {};
TUP tup;
fe<TUP>(r, &tup);
}
GCC 8.2 (and 12.1) compiles the code just fine. However, Clang 11.0.0 (and 14.0.0) complains that the call from fe to feh is ambiguous between void feh(Fn& fn, const std::tuple<H>*) [with Fn = (lambda at <source>:38:14), H = Q] and void feh(Fn& fn, const std::tuple<H, R...>*) [with Fn = (lambda at <source>:38:14), H = Q, R = <>].
https://godbolt.org/z/5E9M6a5c6
Which compiler is right?
How can I write this code so both compilers accept it?
Both if constexpr and fold expressions would work in C++17, but this is a library header included by many projects, and not all of them are compiled with C++17. I need a solution which works in C++11.
Which compiler is right?
Clang is wrong in rejecting the code because the first overload candidate feh(Fn& fn, const std::tuple<H>*) should be preferred over the other candidate feh(Fn& fn, const std::tuple<H, R...>*) since the former is more specialized than the latter.
In other words, the version without the pack is considered more specialized and hence should be preferred if it matches the call.
This is because, basically(roughly) for one function template to be considered more specialized than the other, the latter should be able to accept all the template arguments that the former can accept but not vice-versa.
Now, in your given example the overload feh(Fn& fn, const std::tuple<H, R...>*) can accept(or work with) all template arguments which the former feh(Fn& fn, const std::tuple<H>*) can accept but the reverse is not true. Hence the former is more specialized than the latter. For more technical details of this process, refer to What is the partial ordering procedure in template deduction or from [temp.deduct.partial]/10 which states:
Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G. F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.
(emphasis mine)
clang++ is correct because both functions matches equally good. I'm unsure which compiler that is correct, but...
A C++11 solution could be to just add the requirement that the Rest part must contain at least one type and that is easily done by just adding R1. That would mean that the rest of your code could be left unchanged:
template<typename Fn, typename H, typename R1, typename... R>
inline
void feh(Fn& fn, const std::tuple<H, R1, R...>*)
{
fn(H{});
using Rest = const std::tuple<R1, R...>*;
feh<Fn, R1, R...>(fn, static_cast<Rest>(nullptr));
}
A C++17 solution would be to remove the other feh overloads and use a fold expression:
template <typename Fn, typename... H>
inline void feh(Fn& fn, const std::tuple<H...>*) {
(..., fn(H{}));
}
This is a unary left fold over the comma operator which "unfolded" becomes:
(((fn(H1{}), fn(H2{})), ...), fn(Hn{}))
By far the simplest solution is an if constexpr :
template<typename Fn, typename H, typename... R>
inline
void feh(Fn& fn, const std::tuple<H, R...>*)
{
fn(H{});
if constexpr (sizeof...(R) > 0) {
using Rest = const std::tuple<R...>*;
feh<Fn, R...>(fn, static_cast<Rest>(nullptr));
}
}
and just remove the problematic overload.
How can I write this code so both compilers accept it?
You can write your code without recursion
template<typename Fn, typename ... Ts>
void fe(Fn& fn, const std::tuple<Ts...>* = nullptr)
{
// Trick to simulate fold expression of c++17
const int dummy[] = {0, (static_cast<void>(fn(Ts{})), 0)...};
static_cast<void>(dummy); // Avoid warning about unused variable
}
Which would become, in C++17
template<typename Fn, typename ... Ts>
void fe(Fn& fn, const std::tuple<Ts...>* = nullptr)
{
(static_cast<void>(fn(Ts{})), ...);
// static_cast is here to handle evil overloaded operator comma (for type returned by Fn)
// might be omitted if you know you are not in that pathological case
}
[Demo](fe(r, &tup);)
I was trying out a way to specialize member function based on a class template parameter, without having to use SFINAE on the class (and resulting in either code duplication or creation of another class).
Since two template parameters can't be optional, and argument enable_if is frowned upon in guidelines, so I tried out the (remaining) following 2 ways:
template <bool boolean = true>
struct sample {
constexpr typename std::enable_if<boolean, int>::type bool_check_return(
int s) const noexcept {
return s + 1;
}
constexpr typename std::enable_if<!boolean, int>::type bool_check_return(
int s) const noexcept {
return s;
}
template <typename std::enable_if<boolean, int>::type = 0>
int bool_check_template(
int s) const noexcept {
return s + 1;
}
template <typename std::enable_if<!boolean, int>::type = 0>
int bool_check_template(
int s) const noexcept {
return s;
}
};
Godbolt link
On first look, it doesn't seem obvious to me why the return type SFINAE gives the following error about "overloading is not applicable to functions differing only in return type". SFINAE should have ensured only one copy, not two.
Which part of standard am I unknowingly violating? Or is this a compiler bug? Practically, this would not be an issue in C++17 with if constexpr (and since one form works, I can simply choose that one).
This error is present in C++11 through C++17, which gives a low probability for the compilers to be wrong about this.
error: functions that differ only in their return type cannot be overloaded
constexpr typename std::enable_if<!boolean, int>::type bool_check_return(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
note: previous definition is here
constexpr typename std::enable_if<boolean, int>::type bool_check_return(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
1 error generated.
There is no SFINAE involved here because bool_check_return are not templates themselves. They are just regular overloaded functions that differ only in return type. Making them templates would solve the problem by allowing only one of them:
template<bool enabled = boolean>
constexpr typename std::enable_if<enabled, int>::type bool_check_return(
int s) const noexcept {
return s + 1;
}
template<bool enabled = boolean>
constexpr typename std::enable_if<not enabled, int>::type bool_check_return(
int s) const noexcept {
return s;
}
The compiler is right. In any case, you cannot overload two functions with the same return type, even though only one return type will be valid after substitution.
From [over.load]:
Certain function declarations cannot be overloaded:
Function declarations that differ only in the return type, the exception specification, or both cannot be overloaded.
...
There is no exception to this rule.
I'm writing my own std::async analogue (has to work back to Intel13/gcc 4.4 STL), and this works fine:
template <typename Func, typename ...Args>
struct return_value {
template <typename T>
using decayed = typename std::decay<T>::type;
using type = typename std::result_of<decayed<Func>(decayed<Args>...)>::type;
};
template <typename Func, typename ...Args>
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
return func(args...);
}
void run(int a, double b) {
printf("a: %i b: %f\n", a, b);
}
int main() {
async(run, 1, 3.14);
}
But if I add an overload for run:
void run() {
printf("no args\n");
}
Then it can't properly resolve:
<source>: In function 'int main()':
<source>:27:23: error: no matching function for call to 'async(<unresolved overloaded function type>, int, double)'
async(run, 1, 3.14);
^
<source>:14:43: note: candidate: 'template<class Func, class ... Args> typename return_value<Func, Args>::type async(Func&&, Args&& ...)'
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
^~~~~
<source>:14:43: note: template argument deduction/substitution failed:
<source>:27:23: note: couldn't deduce template parameter 'Func'
async(run, 1, 3.14);
^
Compiler returned: 1
How can I take a function as a template parameter and properly deduce the overload given the arguments?
I personally don't see a way to disambiguate overloads unless you know the return type. You could assume return type void most common and to this then: (I am simplifying your example for brevity)
template <class F, class... Args>
auto async(F f, Args... args)
{
return f(args...);
}
template <class... Args>
auto async(void (*f)(Args...), Args... args)
{
return f(args...);
}
void run();
void run(int, double);
auto test()
{
async(run); // calls run();
async(run, 1, 2.); // calls run(int, double);
}
This does seem kind of fishy and confusing to the user. Why does it work when the function passed returns void and it doesn't if it returns int? So I don't recommend it.
So really the only thing you could do is let it in the hands of the user to figure it out.
So some solutions for the caller of your function:
The good (and ugly) old way: use cast to disambiguate the overload:
async(static_cast<int(*)(int, double)>(run), 1, 2.);
I personally don't like this approach at all. I don't like the verbosity of it and most of all I don't like that I have to be explicit about something that should really be implicit.
The lambda way
async([] { return run(1, 2.); });
I like this. It's not half bad. Still a little bit verbose, but way way better than other alternatives.
The macro way
Yes, macros, in C++. Without further ado, there it is (perfect forwarding omitted for brevity):
#define OVERLOAD(foo) [] (auto... args) { return foo(args...); }
async(OVERLOAD(run), 1, 2.);
I am not going to comment on this one. I leave each and every one of you to judge this macro.
Given a function f(x, y, z) we can bind x to 0, getting a function g(y, z) == f(0, y, z). We can continue doing this and get h() = f(0, 1, 2).
In C++ syntax that would be
#include <functional>
#include <iostream>
void foo(int a, long b, short c)
{
std::cout << a << b << c << std::endl;
}
int main()
{
std::function<void(int, long, short)> bar1 = foo;
std::function<void(long, short)> bar2 = std::bind(bar1, 0, std::placeholders::_1, std::placeholders::_2);
std::function<void(short)> bar3 = std::bind(bar2, 1, std::placeholders::_1);
std::function<void()> bar4 = std::bind(bar3, 2);
bar4(); // prints "012"
return 0;
}
So far so good.
Now say that I want to do the same -- bind the first argument of a function, get the new function back and repeat this process until all arguments are binded -- but generalize it to work not only with a function of 3 arguments as in the C++ example above, but with a function with unknown* number of arguments.
* In C++ there is such thing as variadic arguments and in C++11 there are variadic templates. I'm referring to variadic templates here.
Basically, what I want to be able to do, is to write a function that accepts any std::function and recursively binds the first argument to some value until all arguments are binded and the function can be called.
For the simplicity, let's assume that std::function represents a function taking any integral arguments and returning void.
This code can be considerate to be a generalization of the previous code
#include <functional>
#include <iostream>
// terminating case of recursion
void apply(std::function<void()> fun, int i)
{
fun();
}
template<class Head, class... Tail>
void apply(std::function<void(Head, Tail...)> f, int i)
{
std::function<void(Tail...)> g = std::bind(f, i);
apply<Tail...>(g, ++i);
}
void foo(int a, long b, short c)
{
std::cout << a << b << c << std::endl;
}
int main()
{
std::function<void(int, long, short)> bar1 = foo;
apply<int, long, short>(bar1, 0);
return 0;
}
This code is great. It is exactly what I want. It doesn't compile.
main.cpp: In instantiation of 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = int; Tail = {long int, short int}]':
main.cpp:24:40: required from here
main.cpp:12:56: error: conversion from 'std::_Bind_helper<false, std::function<void(int, long int, short int)>&, int&>::type {aka std::_Bind<std::function<void(int, long int, short int)>(int)>}' to non-scalar type 'std::function<void(long int, short int)>' requested
std::function<void(Tail...)> g = std::bind(f, i);
^
The issue is that you can't just leave out std::placeholders in std::bind call like that. They are required, and number of placeholders in std::bind should match the number of non-binded arguments in the function.
If we change line
std::function<void(Tail...)> g = std::bind(f, i);
to
std::function<void(Tail...)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2);
we see that it successfully passes through the first apply() call, but gets stuck on the second pass, because during the second pass g needs only one placeholder, while we still have two of them in the std::bind.
main.cpp: In instantiation of 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = long int; Tail = {short int}]':
main.cpp:13:30: required from 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = int; Tail = {long int, short int}]'
main.cpp:24:40: required from here
main.cpp:12:102: error: conversion from 'std::_Bind_helper<false, std::function<void(long int, short int)>&, int&, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<std::function<void(long int, short int)>(int, std::_Placeholder<1>, std::_Placeholder<2>)>}' to non-scalar type 'std::function<void(short int)>' requested
std::function<void(Tail...)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2);
^
There is a way to solve that using regular non-variadic templates, but it introduces a limit on how many arguments std::function can have. For example, this code works only if std::function has 3 or less arguments
(replace apply functions in the previous code on these)
// terminating case
void apply(std::function<void()> fun, int i)
{
fun();
}
template<class T0>
void apply(std::function<void(T0)> f, int i)
{
std::function<void()> g = std::bind(f, i);
apply(g, ++i);
}
template<class T0, class T1>
void apply(std::function<void(T0, T1)> f, int i)
{
std::function<void(T1)> g = std::bind(f, i, std::placeholders::_1);
apply<T1>(g, ++i);
}
template<class T0, class T1, class T2>
void apply(std::function<void(T0, T1, T2)> f, int i)
{
std::function<void(T1, T2)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2);
apply<T1, T2>(g, ++i);
}
But the issue with that code is that I would have to define a new apply function to support std::function with 4 arguments, then the same with 5 arguments, 6 and so on. Not to mention that my goal was to not have any hard-coded limit on the number of arguments. So this is not acceptable. I don't want it to have a limit.
I need to find a way to make the variadic template code (the second code snippet) to work.
If only std::bind didn't require to specify placeholders -- everything would work, but as std::bind currently works, we need to find some way to specify the right number of placeholders.
It might be useful to know that we can find the right number of placeholders to specify with C++11's sizeof...
sizeof...(Tail)
but I couldn't get anything worthwhile out of this fact.
First, stop using bind unless you absolutely need to.
// terminating case of recursion
void apply(std::function<void()> fun, int i) {
fun();
}
// recursive case:
template<class Head, class... Tail>
void apply(std::function<void(Head, Tail...)> f, int i) {
// create a one-shot lambda that binds the first argument to `i`:
auto g = [&](Tail&&...tail) // by universal ref trick, bit fancy
{ return std::move(f)(std::move(i), std::forward<Tail>(tail)...);};
// recurse:
apply<Tail...>(g, ++i);
}
next, only type erase if you have to:
// `std::resukt_of` has a design flaw. `invoke` fixes it:
template<class Sig,class=void>struct invoke{};
template<class Sig>using invoke_t=typename invoke<Sig>::type;
// converts any type to void. Useful for sfinae, and may be in C++17:
template<class>struct voider{using type=void;};
template<class T>using void_t=typename voider<T>::type;
// implementation of invoke, returns type of calling instance of F
// with Args...
template<class F,class...Args>
struct invoke<F(Args...),
void_t<decltype(std::declval<F>()(std::declval<Args>()...))>
>{
using type=decltype(std::declval<F>()(std::declval<Args>()...));
};
// tells you if F(Args...) is a valid expression:
template<class Sig,class=void>struct can_invoke:std::false_type{};
template<class Sig>
struct can_invoke<Sig,void_t<invoke_t<Sig>>>
:std::true_type{};
now we have some machinery, a base case:
// if f() is a valid expression, terminate:
template<class F, class T, class I,
class=std::enable_if_t<can_invoke<F()>{}>
>
auto apply(F&& f, T&& t, I&&i)->invoke_t<F()>
{
return std::forward<F>(f)();
}
which says "if we can be invoked, just invoke f.
Next, the recursive case. It relies on C++14 return type deduction:
// if not, build lambda that binds first arg to t, then recurses
// with i(t):
template<class F, class T, class I,
class=std::enable_if_t<!can_invoke<F()>{}, int>>
>
auto apply(F&& f, T&& t, I&&i)
{
// variardic auto lambda, C++14 feature, with sfinae support
// only valid to call once, which is fine, and cannot leave local
// scope:
auto g=[&](auto&&...ts) // takes any number of params
-> invoke_t< F( T, decltype(ts)... ) > // sfinae
{
return std::forward<F>(f)(std::forward<T>(t), decltype(ts)(ts)...);
};
// recurse:
return apply(std::move(g), i(t), std::forward<I>(i));
}
If you want increment, pass [](auto&&x){return x+1;} as 3rd arg.
If you want no change, pass [](auto&&x){return x;} as 3rd arg.
None of this code has been compiled, so there may be typos. I am also worried about the recursion of apply with C++14 return type deduction, that gets tricky sometimes.
If you really have to use bind, you can define your own placeholder types by specializing std::is_placeholder:
template<int N>
struct my_placeholder { static my_placeholder ph; };
template<int N>
my_placeholder<N> my_placeholder<N>::ph;
namespace std {
template<int N>
struct is_placeholder<::my_placeholder<N>> : std::integral_constant<int, N> { };
}
The reason this is useful is that it allows you to then map an integer to a placeholder at compile time, which you can use with the integer_sequence trick:
void apply(std::function<void()> fun, int i)
{
fun();
}
template<class T, class... Ts>
void apply(std::function<void(T, Ts...)> f, int i);
template<class T, class... Ts, int... Is>
void apply(std::function<void(T, Ts...)> f, int i, std::integer_sequence<int, Is...>)
{
std::function<void(Ts...)> g = std::bind(f, i, my_placeholder<Is + 1>::ph...);
apply(g, ++i);
}
template<class T, class... Ts>
void apply(std::function<void(T, Ts...)> f, int i) {
apply(f, i, std::make_integer_sequence<int, sizeof...(Ts)>());
}
Demo. make_integer_sequence and friends are C++14, but can be implemented easily in C++11.
If you're prepared to drop std::bind (which really was a bit of a hacky workaround for pre-C++11 partial applications in my view) this can be quite concisely written:
#include <functional>
#include <iostream>
// End recursion if no more arguments
void apply(std::function<void()> f, int) {
f();
}
template <typename Head, typename ...Tail>
void apply(std::function<void(Head, Tail...)> f, int i=0) {
auto g = [=](Tail&& ...args){
f(i, std::forward<Tail>(args)...);
};
apply(std::function<void(Tail...)>{g}, ++i);
}
void foo(int a, int b, int c, int d) {
std::cout << a << b << c << d << "\n";
}
int main() {
auto f = std::function<void(int,int,int,int)>(foo);
apply(f);
}
Tested working with clang 3.4 and g++ 4.8.2 in C++11 mode. Also on ideone.
You don't need to use std::bind recursively to call some function with a tuple of parameters which values can be evaluated using parameter index:
#include <functional>
#include <utility>
template <typename... Types, std::size_t... indexes, typename Functor>
void apply(std::function<void(Types...)> f, std::index_sequence<indexes...>, Functor&& functor)
{
f(static_cast<Types>(std::forward<Functor>(functor)(indexes))...);
}
template <typename... Types, typename Functor>
void apply(std::function<void(Types...)> f, Functor&& functor)
{
apply(f, std::make_index_sequence<sizeof...(Types)>{}, std::forward<Functor>(functor));
}
Example of use:
void foo(int a, long b, short c)
{
std::cout << a << b << c << std::endl;
}
// ...
std::function<void(int, long, short)> bar = foo;
apply(bar, [](std::size_t index){ return (int)index; });
Live demo
As #T.C. noted in his answer std::make_index_sequence is a C++14 feature but it can be implemented in C++11.
I'm working on a project which involves providing an interface for users to find optima of functions of arbitrary numbers of arguments. Internally, all the mechanism is built around std::tuples of the argument types. I want to provide users the ability to call my optimization routines, though, on functions written in the "usual" style (such as f1 in the example), rather than having to write their functions to be optimized as functions of std::tuple instantiations (such as f2 in the example).
As part of this mechanism, I have written an apply function which unpacks a tuple into the arguments of a given function and calls it.
I have also created a pair of function templates, one forwarding to the other with a lambda wrapper, providing the interface to the optimization routine. A simplified version appears below as tuple_array_map. The intention was to provide SFINAE for selection between the two, depending on whether the function type is callable with a tuple argument, or callable with the unpacked tuple members as arguments. I use dummy template parameters with SFINAE-triggering default arguments for this purpose.
This scheme works perfectly under g++ 4.7 and higher and compiling with -std=c++11 -pedantic -Wall -Wextra -Werror produces no warnings or errors.
However, when trying to compile under clang 5.1 with -std=c++11 (sorry, I'm not a big clang user and I don't know if there's a more appropriate set of options), I get the following output for my example code:
clang_fail.cpp:91:5: error: call to 'tuple_array_map' is ambiguous
tuple_array_map(f2, tuples);
^~~~~~~~~~~~~~~
clang_fail.cpp:59:6: note: candidate function [with Fn = double (*)(const
std::__1::tuple<double> &), TupleArr =
std::__1::array<std::__1::tuple<double>, 5>, $2 = double]
void tuple_array_map(Fn f, const TupleArr& arr)
^
clang_fail.cpp:69:6: note: candidate function [with Fn = double (*)(const
std::__1::tuple<double> &), TupleArr =
std::__1::array<std::__1::tuple<double>, 5>, $2 = double, $3 = void]
void tuple_array_map(Fn f, const TupleArr& arr)
^
clang_fail.cpp:71:5: error: call to 'tuple_array_map' is ambiguous
tuple_array_map([&](const typename TupleArr::value_type& t) {
^~~~~~~~~~~~~~~
clang_fail.cpp:90:5: note: in instantiation of function template specialization
'tuple_array_map<double (*)(double),
std::__1::array<std::__1::tuple<double>, 5>, double, void>' requested here
tuple_array_map(f1, tuples);
^
clang_fail.cpp:59:6: note: candidate function [with Fn = <lambda at
clang_fail.cpp:71:21>, TupleArr = std::__1::array<std::__1::tuple<double>,
5>, $2 = double]
void tuple_array_map(Fn f, const TupleArr& arr)
^
clang_fail.cpp:69:6: note: candidate function [with Fn = <lambda at
clang_fail.cpp:71:21>, TupleArr = std::__1::array<std::__1::tuple<double>,
5>, $2 = double, $3 = void]
void tuple_array_map(Fn f, const TupleArr& arr)
^
The really puzzling part is that it appears to deduce a double return from a call expression that should SFINAE out, unless I've missed something from the standard regarding either template default arguments or SFINAE itself.
Example follows---it's as minimal as I could get it while still triggering the same behavior:
#include <tuple>
#include <array>
#include <utility>
#include <type_traits>
double f1(double x)
{
return x * 2;
}
double f2(const std::tuple<double>& x)
{
return std::get<0>(x) * 2;
}
template<std::size_t N>
struct apply_impl {
template<class F, class Tuple, class... TParams>
static auto apply(F&& fn, Tuple&& t, TParams&&... args)
-> decltype(
apply_impl<N - 1>::apply(
std::forward<F>(fn), std::forward<Tuple>(t),
std::get<N - 1>(std::forward<Tuple>(t)),
std::forward<TParams>(args)...
))
{
return apply_impl<N - 1>::apply(
std::forward<F>(fn), std::forward<Tuple>(t),
std::get<N - 1>(std::forward<Tuple>(t)),
std::forward<TParams>(args)...
);
}
};
template<>
struct apply_impl<0> {
template<class F, class Tuple, class... TParams>
static auto apply(F&& fn, Tuple&&, TParams&&... args)
-> decltype(std::forward<F>(fn)(std::forward<TParams>(args)...))
{
return std::forward<F>(fn)(std::forward<TParams>(args)...);
}
};
template<class F, class Tuple>
auto apply(F&& fn, Tuple&& t)
-> decltype(apply_impl<
std::tuple_size<typename std::decay<Tuple>::type>::value
>::apply(std::forward<F>(fn), std::forward<Tuple>(t)))
{
return apply_impl<
std::tuple_size<typename std::decay<Tuple>::type>::value
>::apply(std::forward<F>(fn), std::forward<Tuple>(t));
}
template<class Fn, class TupleArr,
class = decltype(std::declval<Fn>()(
std::declval<typename TupleArr::value_type>()))>
void tuple_array_map(Fn f, const TupleArr& arr)
{
for (auto i = 0; i < arr.size(); ++i)
static_cast<void>(f(arr[i]));
}
template<class Fn, class TupleArr,
class = decltype(apply(std::declval<Fn>(),
std::declval<typename TupleArr::value_type>())),
class = void>
void tuple_array_map(Fn f, const TupleArr& arr)
{
tuple_array_map([&](const typename TupleArr::value_type& t) {
return apply(f, t);
}, arr);
}
int main()
{
std::array<std::tuple<double>, 5> tuples = {
std::make_tuple(1),
std::make_tuple(2),
std::make_tuple(3),
std::make_tuple(4),
std::make_tuple(5)
};
// "apply" unpacks a tuple into arguments to a function
apply(f1, tuples[0]);
// this call produces an ambiguity one level down under clang
tuple_array_map(f1, tuples);
// this call directly produces an ambiguity under clang
tuple_array_map(f2, tuples);
}
The ambiguity when compiling with libc++ is due to the lack of the standard-mandated explicit specifier on std::tuple's converting constructor (Constructor #2 at cppreference). Consequently, double is implicitly convertible to std::tuple<double> (See this example program) so both of your tuple_apply_map functions are viable.
As a workaround, I suggest creating a needs_apply trait and using that to constrain your tuple_apply_map templates (I'll use tag dispatching):
template<class Fn, class TupleArr>
struct needs_apply {
template <class F=Fn>
static auto test(int) ->
decltype(std::declval<F>()(*std::declval<TupleArr>().begin()), std::false_type{});
static auto test(...) -> std::true_type;
using type = decltype(test(0));
};
template<class Fn, class TupleArr>
void tuple_array_map(Fn f, const TupleArr& arr, std::false_type)
{
for (auto&& i : arr)
static_cast<void>(f(i));
}
template<class Fn, class TupleArr>
void tuple_array_map(Fn f, const TupleArr& arr, std::true_type)
{
tuple_array_map([&](const typename TupleArr::value_type& t) {
return apply(f, t);
}, arr, std::false_type{});
}
template<class Fn, class TupleArr>
void tuple_array_map(Fn&& f, TupleArr&& arr) {
tuple_array_map(std::forward<Fn>(f), std::forward<TupleArr>(arr),
typename needs_apply<Fn,TupleArr>::type{});
}
This works correctly with libc++ and with libstdc++ and even compiling with g++.
According to this answer by Howard Hinnant, this non-conformance of the std::tuple constructor is an extension implemented in libc++ as an experiment.
See also Library Working Group active issue 2051 and the paper N3680 written by Daniel Krügler to address the issue.