SFINAE expression fails to compile with clang - gcc

This looks like an issue in clang (I've already opened a bug here), but I'd like to be sure that I'm not doing a mistake.
Consider the following code:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
It fails to compile with the following error:
8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };
The same code works as expected using the following line instead of (1):
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
The SFINAE expression is almost the same. It is based on a specialization of std::enable_if_t and I would expect the same result (success or failure) for both of the examples.
Are my expectations wrong?
Note that GCC works fine in either cases.

I think this is a gcc bug actually, as a result of [temp.class.spec]:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
In your example, the type of the 3rd template parameter is dependent on a parameter. When you swap it to typename = std::enable_if_t<...>, then this rule no longer applies.
Note: is there any reason to use SFINAE here anyway, as opposed to static_assert-ing?

Related

Recursively unpacking a template pack for a parameter-less function

I'm trying to create a struct template with a variadic template type pack, that can deduct the sum of the size of all types passed in.
Below you find a simplified example, in the real-world context, the size computed is used to create further member objects.
template <typename... Types>
struct OverallSize
{
template <typename FirstType, typename... NextTypes>
static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
template <typename LastType>
static constexpr size_t sizesum() { return sizeof (LastType); }
static constexpr size_t size = sizesum<Types...>();
};
// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64
I'm used to this recursive parameter unpacking approach when it comes to argument lists and assumed this works as well with argument-less functions and explicit template specification. However I get the following error when compiling with clang
Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]
So it seems as if the last recursion iteration doesn't work here – not sure why the compiler doesn't simply chose the most obvious choice: The one with only one template type – just as it would happen if there was an actual template argument passed to the function.
So, what do I have to do to make this compile and work as desired?
For C++14 you can use SFINAE:
template <
typename FirstType,
typename... NextTypes,
std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
return sizeof (FirstType) + sizesum<NextTypes...>();
}
this template will be considered only if parameters pack has size >= 1.
Demo

How can I use Boost.Hana to determine whether a functor has a call operator that can be invoked with a particular template argument?

In my application, I want to determine at compile time whether an arbitrary functor type Func has a nullary call operator that can be invoked with a given explicit template argument T. Based on a previous SO answer that I found, I came up with the following:
#include <boost/hana.hpp>
#include <iostream>
#include <type_traits>
namespace hana = boost::hana;
namespace detail
{
template <typename T>
auto can_call = hana::is_valid([](auto &&f) ->
decltype(f.template operator()<T>()) { });
}
template <typename Func, typename T>
constexpr auto can_call() ->
decltype(detail::can_call<typename std::remove_reference<T>::type>(
std::declval<Func>())) { return {}; }
struct foo
{
template <typename T, typename =
std::enable_if_t<!std::is_same<T, char>::value>>
void operator()() const { }
};
int main()
{
std::cout << "char: " << can_call<foo, char>() << std::endl;
std::cout << "int: " << can_call<foo, int>() << std::endl;
}
I would expect this example to print out:
char: 0
int: 1
Since the char template argument type is explicitly enable_if-ed out in foo. I've tried the following compilers:
Apple clang v8.0.0: The example compiles and runs as expected.
mainline clang v3.9.1+ (via Wandbox): The example compiles and runs as expected.
mainline clang v3.6.0 - v3.8.1 (via Wandbox): The compiler dies with an internal error.
g++ 7.0 trunk, 20170410 (via Wandbox): The compilation fails with the following errors:
dd.cc: In instantiation of ‘auto detail::can_call<char>’:
dd.cc:15:14: required by substitution of ‘template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call() [with Func = foo; T = char]’
dd.cc:25:50: required from here
dd.cc:10:10: error: ‘auto detail::can_call<char>’ has incomplete type
auto can_call = hana::is_valid([](auto &&f) -> decltype(f.template operator()<T>()) { });
^~~~~~~~
dd.cc: In function ‘int main()’:
dd.cc:25:50: error: no matching function for call to ‘can_call<foo, char>()’
std::cout << "char: " << can_call<foo, char>() << std::endl;
^
dd.cc:14:16: note: candidate: template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call()
constexpr auto can_call() ->
^~~~~~~~
dd.cc:14:16: note: substitution of deduced template arguments resulted in errors seen above
dd.cc: In instantiation of ‘auto detail::can_call<int>’:
dd.cc:15:14: required by substitution of ‘template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call() [with Func = foo; T = int]’
dd.cc:26:48: required from here
dd.cc:10:10: error: ‘auto detail::can_call<int>’ has incomplete type
auto can_call = hana::is_valid([](auto &&f) -> decltype(f.template operator()<T>()) { });
^~~~~~~~
dd.cc:26:48: error: no matching function for call to ‘can_call<foo, int>()’
std::cout << "int: " << can_call<foo, int>() << std::endl;
^
dd.cc:14:16: note: candidate: template<class Func, class T> constexpr decltype (can_call<typename std::remove_reference<_To>::type>(declval<Func>())) can_call()
constexpr auto can_call() ->
^~~~~~~~
dd.cc:14:16: note: substitution of deduced template arguments resulted in errors seen above
It seems to not like my use of hana::is_valid() to determine whether the specified operator exists. However, I think the way I'm using it is consistent with its intended use.
Is this a bug in gcc, a more lenient implementation in contemporary clang versions, or did I implement this type of check incorrectly? It seems like this is definitely within Hana's wheelhouse; I'm just trying to wrap my head around its new model of constexpr metaprogramming.
Here is a workaround that uses a struct "functor" instead of a lambda and an extra layer of indirection for the type of the is_valid instance to appease gcc.
namespace detail
{
template <typename T>
struct check_can_call {
template <typename F>
constexpr auto operator()(F&& f) ->
decltype(f.template operator()<T>()) { }
};
template <typename T>
using is_call_valid = decltype(hana::is_valid(check_can_call<T>{}));
template <typename T>
constexpr is_call_valid<T> can_call{};
}

g++ fails to look up static functions in a template class, is it a bug or standard defined?

When I try some C++11 code like following, it passed in all clang++ available to me that support C++11, but it failed to compile in g++-4.8, g++-4.9 and g++-5.0.
#include <type_traits>
#include <vector>
template <class C, class First, class Last>
struct HasInsertEnd {
template <class U>
static std::false_type Check(...);
template <class U>
static auto Check(U val)
-> decltype(val.insert(val.end(), std::declval<First>(),
std::declval<Last>()),
std::true_type{});
template <class U>
using Deduce = decltype(Check<U>(std::declval<U>()));
using type = typename Deduce<C>::type;
static constexpr bool value = type::value;
};
int main(int argc, char* argv[]) {
static_assert(!HasInsertEnd<int, int, int>::value, "...");
static_assert(HasInsertEnd<std::vector<int>, const int*, const int*>::value,
"...");
return 0;
}
g++ will report errors like:
‘Check’ was not declared in this scope
If I change the calling of Check in the Deduce to HasInsertEnd::Check, both g++ and clang++ will be happy.
I know little about dependent name lookup. The problem is, which behavior is standard?
This is a bug in GCC, and can be shown to be a bug in GCC even without deferring to the standard.
template <typename T>
struct f { typedef int type; };
template <typename T>
struct S {
template <typename U>
static f<U> f();
template <class U>
using u = typename decltype(f<U>())::type;
using t = u<T>;
};
S<int>::t main() { }
This is rejected the same way in GCC 4.7.4 and GCC 5, with "error: ‘f’ was not declared in this scope". That's just nonsense. Even if the static member function should somehow not be visible, there is still a global type by the same name that would be found instead. It gets even better, though: with that global type, you get:
test.cc: In substitution of ‘template<class T> template<class U> using u = typename decltype (f<U>())::type [with U = T; T = T]’:
test.cc:12:20: required from here
test.cc:10:36: error: ‘f’ was not declared in this scope
using u = typename decltype(f<U>())::type;
^
test.cc:10:36: note: suggested alternative:
test.cc:2:12: note: ‘f’
struct f { typedef int type; };
^
test.cc:15:13: error: ‘t’ in ‘struct S<int>’ does not name a type
S<int>::t main() { }
^
That's right, it's suggesting that f can be corrected by spelling it f.
I don't see any problem with your code, and if it isn't a known bug, I encourage you to report it. and it's been reported as a bug before.
Oddly, as noted in the comments, GCC 4.8.4 and GCC 4.9.2 do find a global f. However, if the global f is a type, then they still reject the program, with "error: missing template arguments" even though the template argument is provided, so it's still clearly a bug in GCC.

is_enum causing incorrect behavior for SFINAE application?

I have been playing around with SFINAE applied to the "has_member" type of structs as described here.
So I was trying to use some of the features of c++11 to make these solutions simpler. Having some problems with checking for existence of an enum, but I can't seem to locate my logic error here. Code is:
#include<iostream>
template<typename T >
struct has_enum_name
{
private:
// ***** this is the line that isn't working *****
// If U has an enum "name", then I expect is_enum to return true…
// Then I expect enable_if<>::type to be std::true_type…etc. This isn't what happens.
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
static constexpr bool is_enum()
{
return std::is_enum<typename T::name>::value;
}
};
template<typename T >
struct has_enum_name_2
{
private:
template<typename U> static auto test(int) -> decltype(
std::enable_if<true, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
};
struct Foo
{
enum class name
{
enum1,
enum2
};
};
int main()
{
std::cout<<"std::is_enum<Foo::name>::value = "<<std::is_enum<Foo::name>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::value = "<<has_enum_name<Foo>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::is_enum() = "<<has_enum_name<Foo>::is_enum()<<std::endl;
std::cout<<"has_enum_name_2<Foo>::value = "<<has_enum_name_2<Foo>::value<<std::endl;
}
Running this using gcc 4.9.2 gives
$ ./a.out
std::is_enum<Foo::name>::value = 1
has_enum_name<Foo>::value = 0
has_enum_name<Foo>::is_enum() = 1
has_enum_name_2<Foo>::value = 1
The first output line verifies that the std::is_enum works correctly for the Foo::name enum.
The second line outputs the results of struct constexpr "has_enum_name::value". I am just trying to use std::enable_if in conjunction with std::is_enum to make the decltype return something…in this case std::true_type(). As you can see, the output returns false…so the line:
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
isn't working out like i think it should. I think that is_enum should return true, which means that enable_if should return true_type, and decltype should return true_type().
Next output is just a check to see if std::is_enum<> is working correctly in the struct…it is.
Next output is just a copy of the "has_enum_name" struct, but I replaced the is_enum<> in the suspect line with a hard coded "true"…and it works correctly.
So for some reason, it appears that is_enum is not working returning true. Any ideas what I am doing wrong here?
When you encounter a problem like this, let the compiler help you. Remove the (...) overload to force a compilation error, and see what GCC tells you:
test.cc: In instantiation of ‘constexpr const bool has_enum_name<Foo>::value’:
test.cc:51:71: required from here
test.cc:18:33: error: no matching function for call to ‘has_enum_name<Foo>::test(int)’
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
^
test.cc:18:33: note: candidate is:
test.cc:12:36: note: template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = U; T = Foo]
template<typename U> static auto test(int) -> decltype(
^
test.cc:12:36: note: template argument deduction/substitution failed:
test.cc: In substitution of ‘template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = Foo]’:
test.cc:18:33: required from ‘constexpr const bool has_enum_name<Foo>::value’
test.cc:51:71: required from here
test.cc:13:83: error: dependent-name ‘std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ is parsed as a non-type, but instantiation yields a type
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
^
test.cc:13:83: note: say ‘typename std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ if a type is meant
That's exactly what's wrong: you merely forgot to add typename. T::type() could be valid if type is a non-type: it could just be a function call. That's how the compiler is parsing it.
By the way, decltype(typename T::type()) seems somewhat pointless unless you're specifically trying to check whether the type is default-constructible, and that's not what you're going for here. You can simply use typename T::type directly, like so:
template<typename U> static auto test(int) ->
typename std::enable_if<std::is_enum<typename U::name>::value, std::true_type>::type;
and if you had tried that without the typename, you would've immediately got a useful error message.
Your initialisation of value is also needlessly complicated, since you already know you're dealing with false_type or true_type: both of those have a value member you can use.
static constexpr bool value = decltype(test<T>(0))::value;

Creating a new tuple class by popping the last type

I tried the following code but it gives:
main.cpp:29:22: error: aggregate 'pop<std::tuple<int, char, float> > p' has incomplete type and cannot be defined
What am I missing?
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<tuple<Ts..., E>> {
using result = tuple<Ts...>;
};
tuple<int, char, float> t;
typename pop<decltype(t)>::result p;
If Ts... must be at the end in a type list, why does it work in this example from http://en.cppreference.com/w/cpp/language/parameter_pack:
template<class A, class B, class...C> void func(A arg1, B arg2, C...arg3)
{
container<A,B,C...> t1; // expands to container<A,B,E1,E2,E3>
container<C...,A,B> t2; // expands to container<E1,E2,E3,A,B>
container<A,C...,B> t3; // expands to container<A,E1,E2,E3,B>
}
tuple<Ts..., E> is a non-deduced context. [temp.deduct.type]/9:
If P has a form that contains <T> or <i>, then each argument Pi of the respective template argument list P is compared with the corresponding argument Ai of the corresponding template argument list of A. If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context.
That means that your partial specialization is never matched.
With C++14, one could use
template <class T, class=std::make_index_sequence<std::tuple_size<T>::value-1>>
struct pop;
template <typename Tuple, std::size_t... indices>
struct pop<Tuple, std::index_sequence<indices...>>
{
using type = std::tuple<std::tuple_element_t<indices, Tuple>...>;
};
template <typename T>
using pop_t = typename pop<T>::type;
Such that
using t = std::tuple<int, char, float>;
static_assert( std::is_same<pop_t<t>, std::tuple<int, char>>{}, "" );
Compiles.
Demo.
Ts... must be the last element of a type list if you want it to be deduced. tuple<Ts...,E> will not deduce Ts... to be all but the last, but rather never match anything.
Getting rid of the last argument is a bit tricker. live example:
#include <iostream>
#include <tuple>
#include <iostream>
namespace details {
template<class Lhs, class Rhs>
struct pop_helper;
template<template<class...>class Tup, class L0, class...Lhs, class...Rhs>
struct pop_helper<Tup<L0,Lhs...>, Tup<Rhs...>>:
pop_helper<Tup<Lhs...>, Tup<Rhs...,L0>>
{};
template<template<class...>class Tup, class L0, class...Rhs>
struct pop_helper<Tup<L0>, Tup<Rhs...>> {
using type=Tup<Rhs...>;
};
}
template <typename T>
struct pop;
template<template<class...>class Tup, class...Ts>
struct pop<Tup<Ts...>>:
details::pop_helper<Tup<Ts...>,Tup<>>
{};
template<typename T>
using pop_t=typename pop<T>::type;
std::tuple<int, char, float> t;
typedef pop_t<decltype(t)> p;
int main() {
p x = std::make_tuple( 7, 'x' );
std::cout << std::get<0>(x) << std::get<1>(x) << std::tuple_size<p>{} << "\n";
}
pop_helper moves the types over one at a time to the right hand side, until there is only one type left on the left hand side. Then it returns the right hand side type.
pop just passes the tuples over.
I used template<class...>class Tup instead of std::tuple, because why not support almost every template instead of just std::tuple?
pop_t gets rid of the annoying typename spam at point of use.
I use the inhertance-as-type-map-forwarding pattern, which saves on typing. With a type-map, the structure:
template<class X>
struct bob: foo<X> {};
can be read as bob<X> is foo<X>. The alternative is the more verbose
template<class X>
struct bob {
using type = typename foo<X>::type;
};
expanding variardic type lists is different than matching them. When it was designed, matching was kept simple in order to make compiler vendors be able to implement the feature. There may even be thorny issues beyond "it is tricky" down that path.
Another C++11 way to skin this cat:
#include <tuple>
template<class Tuple>
struct pop;
template<>
struct pop<std::tuple<>>
{
using type = std::tuple<>;
};
template<typename T1>
struct pop<std::tuple<T1>>
{
using type = std::tuple<>;
};
template<typename First, typename... Rest>
struct pop<std::tuple<First,Rest...>>
{
using type =
decltype(std::tuple_cat(
std::declval<std::tuple<First>>(),
std::declval<typename pop<std::tuple<Rest...>>::type>()));
};
// Test...
static_assert(std::is_same<pop<std::tuple<>>::type,std::tuple<>>::value,"");
static_assert(std::is_same<pop<std::tuple<int>>::type,std::tuple<>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char>>::type,std::tuple<int>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float>>::type,
std::tuple<int,char>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float,double>>::type,
std::tuple<int,char,float>>::value,"");
This is the solution I had come up with:
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<std::tuple<E, Ts...>> {
using type = decltype(tuple_cat(
declval<tuple<E>>(),
declval<typename pop<tuple<Ts...>>::type>()
));
};
template <typename E>
struct pop<std::tuple<E>> {
using type = std::tuple<>;
};

Resources