I wrote type checking constexpr function.
It the type is type1 or type2 then returns true, otherwise returns false.
Here is the code. It works as I expected.
#include <type_traits>
struct type1{};
struct type2{};
struct type3{};
template <typename T>
constexpr bool is_type1or2() {
return std::is_same_v<T, type1> || std::is_same_v<T, type2>;
}
static_assert(is_type1or2<type1>());
static_assert(is_type1or2<type2>());
static_assert(!is_type1or2<type3>());
int main(){}
https://godbolt.org/z/dncKo1Pbb
Now, type1 is changed to template that has non-type parameter.
How to do the same type checking?
#include <type_traits>
template <std::size_t N>
struct type1{};
struct type2{};
struct type3{};
template <typename T>
constexpr bool is_type1or2() {
return std::is_same_v<T, type2>;
}
template <typename T, std::size_t N>
constexpr bool is_type1or2() {
return std::is_same_v<T, type1<N>>;
}
// I want to write as follows but I couldn't find a way, so far.
// static_assert(is_type1or2<type1<42>>());
// so I pass explicit second template argument 42.
static_assert(is_type1or2<type1<42>, 42>());
static_assert(is_type1or2<type2>());
static_assert(!is_type1or2<type3>());
int main(){}
https://godbolt.org/z/G1o5447z8
I tried but I can't eliminate the second template argument. It avoids generic code.
Is there any good way to check the type is type1<anyN> or type2 ?
In my actual case, I have 20 of non template types like type2 and 20 of template types like type1. And half of them need to match. I want to avoid code repeatation as long as I can.
Clarify requirement
For template type type1<N>, N is not important. Both template is type1 is important. So the result of is_type1or2<type1<10>>() and is_type1or2<type1<20>>() are always same. I don't need to define individual template argument specialization based matching.
You can make your own type trait:
template <typename>
struct is_type1 : public std::false_type {};
template <std::size_t N>
struct is_type1<type1<N>> : public std::true_type {};
This still requires the usage to instantiate an actual type:
static_assert(is_type1or2<type1<42>>());
Demo
You can also do it this way:
template <template<std::size_t> class>
struct is_type1 : public std::false_type {};
template <>
struct is_type1<type1> : public std::true_type {};
But then is_type1 can only be instantiated with templates that have a std::size_t parameter. So you can no longer do is_type1<T>::value || std::is_same_v<T, type2> because is_type1 only accepts templates while std::is_same_v only accepts types, and T cannot be both. It can work if type2 is also defined like type1, that is:
template <std::size_t N>
struct type1{};
template <std::size_t N>
struct type2{};
template <template<std::size_t> class>
struct is_type1or2_t : public std::false_type {};
template <>
struct is_type1or2_t<type1> : public std::true_type {};
template <>
struct is_type1or2_t<type2> : public std::true_type {};
template <template<std::size_t> class T>
constexpr bool is_type1or2() {
return is_type1or2_t<T>::value;
}
But you still can't use is_type1or2 with type3, even in a static_assert. So you also need to add an overload for simple types:
template <typename>
constexpr bool is_type1or2() {
return false;
}
Demo
If you also need an instantiation of type1 or type2 to match, you can add yet another type trait:
template <typename>
struct is_type1or2_instantiation_t : public std::false_type {};
template <std::size_t N>
struct is_type1or2_instantiation_t<type1<N>> : public std::true_type {};
template <std::size_t N>
struct is_type1or2_instantiation_t<type2<N>> : public std::true_type {};
// [...]
template <typename T>
constexpr bool is_type1or2() {
return is_type1or2_instantiation_t<T>::value;
}
Demo
This can be solved easily if you change the syntax of the static_assert to accept the type as a function argument, as this will allow function template argument deduction (see Takatoshi Kondo's answer).
However, this can also be solved by writing a template that checks whether a type is an instantiation of a template:
template<template <std::size_t> typename, typename>
struct is_instance_of : std::false_type {};
template<template <std::size_t> typename T, std::size_t N>
struct is_instance_of<T, T<N>> : std::true_type {};
Now is_instance_of can be used in the function (without argument deduction) as:
template <typename T>
constexpr bool is_type1or2() {
return
is_instance_of<type1, T>::value // repeat for other templates that take a size_t parameter
or std::is_same_v<T, type2>; // repeat for non-template types
}
If you have other template types that you want to allow (i.e. templates that take parameters other than a size_t), you can edit is_instance_of as needed.
Here's a demo.
After some of try and error, I finally found the solution.
In my actual case, I have 20 of non template types like type2 and 20 of template types like type1. And half of them need to match. I want to avoid code repeatation as long as I can.
In order to demonstrate my situation above, I added type4 non-type template similar to type1. And type1, type2 and type4 need to match.
#include <type_traits>
template <std::size_t N>
struct type1{};
struct type2{};
struct type3{};
template <std::size_t N> // type4 added
struct type4{};
// overload for non-templates
template <typename T>
constexpr bool is_type1or2or4(T) { // or 4 added
return std::is_same_v<T, type2>;
}
// overload for templates
template <template <std::size_t> typename T, std::size_t N>
constexpr bool is_type1or2or4(T<N>) { // or 4 added
return
std::is_same_v<T<N>, type1<N>> ||
std::is_same_v<T<N>, type4<N>>;
}
static_assert(is_type1or2or4(type1<42>()));
static_assert(is_type1or2or4(type2()));
static_assert(!is_type1or2or4(type3()));
static_assert(is_type1or2or4(type4<12>()));
int main(){}
https://godbolt.org/z/17GbGK738
I use template argument deduction. Then I can extract N and pass it as template argument.
There are two overload funtion templates. One of for non-template types, the other is template types.
It works fine.
I have a Writer struct to do some serialization
template<typename T>
struct Writer {}; // only specialized version has ::wrap_t
template<>
struct Writer <int> {
typedef int wrap_t;
};
template <typename T>
using Writer_wrap_t = typename Writer<T>::wrap_t;
template<>
struct Writer<float> {
typedef float wrap_t;
};
And I want to know whether a type has a specialized Writer. The code does not work as expect:
template<typename T, typename U = Writer_wrap_t <T>>
struct has_writer : std::true_type {};
template<typename T>
struct has_writer<T, void> : std::false_type {};
int main() {
bool b = has_writer <double>::value;
// error C2794: 'wrap_t': is not a member of any direct or indirect base class of 'Writer<T>'
// error C2976: 'has_reflect': too few template arguments
// error C2938: 'Writer_wrap_t ' : Failed to specialize alias template
}
I suppose that has_writer<double> didn't use the specialized version struct has_writer<T, void> : std::false_type {};?
But now there is a substitution failure for the first one, shouldn't the compiler try to instantiate the second version?
You're not using SFINAE correctly. The typical pattern is to define a primary template where the second template parameter is void
template<typename T, typename = void>
struct has_writer : std::false_type {};
and then specialize the template using std::void_t of whatever type you want to check as the second parameter
template<typename T>
struct has_writer<T, std::void_t<Writer_wrap_t <T>>> : std::true_type {};
If the type you pass to void_t is well-formed, the specialization is chosen, which is the true case, otherwise the primary is chosen, which is the false case. Writer_wrap_t itself is only well-formed if the type passed to it has a member typedef wrap_t.
I have many EnableIf traits that basically check whether the input type satisfies an interface. I was trying to create a generic Resolve trait that can be used to transform those into a boolean trait.
Something like this - https://wandbox.org/permlink/ydEMyErOoaOa60Jx
template <
template <typename...> class Predicate,
typename T,
typename = std::void_t<>>
struct Resolve : std::false_type {};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, Predicate<T>> : std::true_type {};
Now if you have an EnableIf trait like so
template <typename T>
using EnableIfHasFoo = std::void_t<decltype(std::declval<T>().foo())>;
You can create a boolean version of that very quickly
template <typename T>
struct HasFoo : Resolve<EnableIfHasFoo, T> {};
Or the analogous variable template.
But for some reason the partial specialization is not working as expected. Resolve does not work as intended. See the output here - https://wandbox.org/permlink/ydEMyErOoaOa60Jx. The same thing implemented "manually" works - https://wandbox.org/permlink/fmcFT3kLSqyiBprm
I am resorting to manually defining the types myself. Is there a detail with partial specializations and template template arguments that I am missing?
I cannot find the exact reason why your example don't work. If you want to dig more into the details of std::void_t, here's an interesting explanation
Even if I cannot explain it in depth, I would like to add another reliable syntax that is used in the detection idiom.
template<
template <typename...> class Predicate,
typename T,
typename = void>
struct Resolve : std::false_type {};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, std::void_t<Predicate<T>>> : std::true_type {};
template <typename T>
using EnableIfHasFoo = decltype(std::declval<T>().foo());
live on compiler explorer
The reason why your approach will fail is that Predicate<T>> in the third template parameter is not a non-deduced context. This causes the deduction to directly fail (see [temp.alias]/2), instead of using the deduced template arguments from elsewhere as in a non-deduced context.
You can wrap your Predicate<T>> to a non-deduced context to make it work:
template<class T>
struct identity {
using type = T;
};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, typename identity<Predicate<T>>::type> : std::true_type {};
Live Demo
Because inside a non-deduced context, the deduction won't happen for Predicate<T> part, instead, it will use the Predicate and T obtained from elsewhere.
As for why the usual detection-idiom (see Guillaume Racicot's answer) will work, it is because std::void_t as a template alias, will be replaced by void in deduction phase (see [temp.alias]/2), thus no deduction will happen.
Here are some examples to illustrate it more clearly:
template<class T>
using always_int = int;
template<template<class> class TT>
struct deductor {};
template<template<class> class TT, class T>
void foo(T, deductor<TT>) {}
template<template<class> class TT, class T>
void bar(T, deductor<TT>, TT<T>) {}
template<class T>
void baz(T, always_int<T>) {}
int main() {
// ok, both T and TT are deduced
foo(0, deductor<always_int>{});
// ERROR, TT<T> is NOT a non-deduced context, deduction failure
bar(0, deductor<always_int>{}, 0);
// ok, T is deduced, always_int<T> is replaced by int so no deduction
baz(0, 0);
}
I want to be able to specialize a type based on whether a container has a specified typedef for example
class SomethingElse {};
class Something {
using Type = int;
};
static constexpr bool value = ChooseIfType<Something>::value;
Is there a way for ChooseIfType to return false when the type does not have the typedef Type?
I feel like there is an easy way to do this but I cannot figure it out.
Thanks!
Just use std::void_t (or a C++11 alternative):
template<typename T, typename = std::void_t<>>
struct ChooseIfType : std::false_type {};
template<typename T>
struct ChooseIfType<T, std::void_t<typename T::Type>> : std::true_type {};
live demo
The solution makes use of SFINAE. The default is never malformed and creates a trait with value false. The compiler tries to match all template specializations (only one in this case). If T has a member type Type, then ChooseIfType<T, void_t<typename T::Type>> is more specialized than ChooseIfType<T, void_t<>>. If it doesn't, then it's not a viable specialization and the default is selected, but Substitution Failure Is Not An Error.
as per cppreference, a C++11 void_t implementation could look like this:
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
I'm trying to write a metafunction that checks whether all types passed as a variadic template parameter are distinct. It seems that the most performant way to do this is to inherit from a set of classes and detect, whether there is an error.
The problem is that compilation fails in the following code, while I would expect SFINAE to work.
Edit. The question is not "how to write that metafunction" but "how do I catch that double inheritance error and output false_type when it happens". AFAIK, it's possible only with SFINAE.
template <typename T>
struct dummy {};
// error: duplicate base type ‘dummy<int>’ invalid
template <typename T, typename U>
struct fail : dummy<T>, dummy<U> {};
template <typename T>
true_type test(fail<T, T> a = fail<T, T>());
false_type test(...);
int main() {
cout << decltype(test<int>())::value << endl;
}
Live version here.
Edit. Previously I've tried to do this with specialization failure, but it didn't work either with the same compilation error.
template <typename T>
struct dummy {};
template <typename T, typename U>
struct fail : dummy<T>, dummy<U>, true_type {};
template <typename T, typename U = void>
struct test : false_type {};
template <typename T>
struct test<T, typename enable_if<fail<T, T>::value, void>::type> : true_type {};
Live version here.
You can't catch duplicate inheritance with SFINAE, because it is not one of the listed reasons for deduction to fail under 14.8.2p8 [temp.deduct]; equally, it is because the error occurs outside the "immediate context" of template deduction, as it is an error with the instantiation of your struct fail.
There is however a very similar technique which is suitable for use in your case, which is to detect an ambiguous conversion from a derived class to multiple base classes. Clearly the ambiguous base classes can't be inherited directly from a single derived class, but it works fine to inherit them in a linear chain:
C<> A<int>
| /
C<int> A<char>
| /
C<char, int> A<int>
| /
C<int, char, int>
Now a conversion from C<int, char, int> to A<int> will be ambiguous, and as ambiguous conversion is listed under 14.8.2p8 we can use SFINAE to detect it:
#include <type_traits>
template<class> struct A {};
template<class... Ts> struct C;
template<> struct C<> {};
template<class T, class... Ts> struct C<T, Ts...>: A<T>, C<Ts...> {};
template<class... Ts> void f(A<Ts>...);
template<class... Ts> std::false_type g(...);
template<class... Ts> decltype(f((A<Ts>(), C<Ts...>())...), std::true_type()) g(int);
template<class... Ts> using distinct = decltype(g<Ts...>(0));
static_assert(distinct<int, char, float>::value, "!!");
static_assert(!distinct<int, char, int>::value, "!!");
THE ERROR
prog.cpp: In instantiation of ‘struct fail<int, int>’:
prog.cpp:23:29: required from here
prog.cpp:9:8: error: duplicate base type ‘dummy<int>’ invalid
struct fail : dummy<T>, dummy<U> {};
As stated in the above diagnostic you cannot explicitly inherit from the same base more than once in a base-specifier-list, and since T and U can possibly be of the same type.. BOOM.
WAIT, HOLD UP; WHAT ABOUT SFINAE?
SFINAE is only checked in the immediate context of the template itself, error that happens beyond the declaration are not suitable to trigger a SFINAE.
14.8.2p8 Template argument deduction [temp.deduct]
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguemts.
Only invalid types and expressions in the immediate context of the function type and its templat eparameter types can result in a deduction failure.
The ill-formed inheritance does not happen in the immediate context, and the application is ill-formed.
To answer your question explicitly: since inheritance never happens in the declaration of a certain function, the ill-formed inheritance itself cannot be caught by SFINAE.
Sure, you can ask for the compiler to generate a class that uses inheritance, by instantiation it in the function declaration, but the actual (ill-formed) inheritance is not in the immediate context.
As I understand, you want a traits to check if all type are differents,
following may help:
#include <type_traits>
template <typename T, typename ...Ts> struct is_in;
template <typename T> struct is_in<T> : std::false_type {};
template <typename T1, typename T2, typename ... Ts>
struct is_in<T1, T2, Ts...> : std::conditional<std::is_same<T1, T2>::value, std::true_type, is_in<T1, Ts...>>::type {};
template <typename ... Ts> struct are_all_different;
template <> struct are_all_different<> : std::true_type {};
template <typename T> struct are_all_different<T> : std::true_type {};
template <typename T1, typename T2, typename ... Ts> struct are_all_different<T1, T2, Ts...> :
std::conditional<is_in<T1, T2, Ts...>::value, std::false_type, are_all_different<T2, Ts...>>::type {};
static_assert(are_all_different<char, int, float, long, short>::value, "type should be all different");
static_assert(!are_all_different<char, int, float, char, short>::value, "type should not all different");
What about a simple std::is_same<>? As far as I can see, it directly models the desired behaviour of your class.
So try something like this:
template<typename T, typename U>
fail
{
fail(const T &t, const U &u)
{
static_assert(std::is_same<T,U>::value,"T and U must have a distinct type");
}
};
Or even better, directly use std::is_same<T,U> in your code.
EDIT: Here is a solution inspired by Jarod42's but which uses only a single class (to make it clearer: this is an answer to the question how to write a variadic class template which detects whether all given types are distinct, which seemed to be the desired goal in one of the early versions of the original question):
#include <type_traits>
template <typename ...Ts> struct are_all_different {};
template <> struct are_all_different<> {static const bool value=true;};
template <typename T> struct are_all_different<T> {static const bool value=true;};
template <typename T1, typename T2>
struct are_all_different<T1, T2>
{
static const bool value = !std::is_same<T1, T2>::value;
};
template <typename T1, typename T2, typename ...Ts>
struct are_all_different<T1,T2,Ts...>
{
static const bool value = are_all_different<T1, T2>::value
&& are_all_different<T1, Ts...>::value
&& are_all_different<T2, Ts...>::value;
};
static_assert(are_all_different<char, int, float, long, short>::value, "type should be all different");
static_assert(!are_all_different<char, int, float, char, short>::value, "type should not all different");
In the end, for n variadic template arguments, this should check for equality of all of the n*(n+1)/2 combinations.
I don’t really understand what you are trying to achieve, but I can help you with the error
template <typename T, typename U>
struct fail : dummy<T>, dummy<U> {};
template <typename T>
struct fail<T, T> : dummy<T> {};
The error is because when you instantiate fail with T and U the same you basically inherit from the same class twice, which is illegal, so you need to create a specialization to take care of this case.