I aim to implement a structure template that can be used to detect either if a template substitution is well formed or will fail. An example of usage is to provide two versions of template functions depending on whether the template parameter is comparable or not.
It can be solved quite easily if one provides structures for each scenario explicitly, e.g. whether there exists an equality operator for the template type, as shown here. But I failed to implement a structure that would accept (almost) arbitrary construct as a template argument.
The "best" approach I have reached so far uses template template argument. It compiles, but it does not fit the case when the argument substitution should be well formed.
#include <iostream>
#include <type_traits>
template <typename T = void, typename...>
using Enable = T;
template <bool Cond, typename T = void>
using Enable_if = typename std::enable_if<Cond, T>::type;
template <typename T, template<typename> class X, typename = void>
struct Is_enabled : std::false_type {};
template <typename T, template<typename> class X>
struct Is_enabled<T, X, Enable<X<T>>> : std::true_type {};
/// An example of construct
template <typename T>
using Equals = decltype(std::declval<T>() == std::declval<T>());
template <typename T>
using Enabled_eq = Enable_if<Is_enabled<T, Equals>::value>;
template <typename T>
using Disabled_eq = Enable_if<!Is_enabled<T, Equals>::value>;
template <typename T>
Enabled_eq<T> foo()
{
std::cerr << "enabled!" << std::endl;
}
template <typename T>
Disabled_eq<T> foo()
{
std::cerr << "disabled!" << std::endl;
}
struct A {};
int main(int /*argc*/, const char* /*argv*/[])
{
foo<int>(); /// should print "enabled!"
foo<A>(); /// should print "disabled!"
return 0;
}
In case of int, it should obviously print "enabled!", and in case of A it should print "disabled!". But it always prints "disabled!", so the specialization of Is_enabled is never done.
Am I somewhat close to a correct solution, or will it be more complicated?
The third template parameter of Is_enabled defaults to void. This is what the compiler will use in the Is_enabled<T, Equals> instantiation. That is, Is_enabled<T, X, Enable<X<T>>> : std::true_type {}; can be used only if Enable<X<T>> evaluates to void. By explicitly passing a template argument X<T> to class template Enable declared as:
template <typename T = void, typename...>
using Enable = T;
you actually create an alias for X<T> itself, and the void type (the default one, needed for the dispatching to work) is not used at all. In your case, X<T> is the result of the decltype specifier. For foo<A>() it does lead to instantiation failure. For foo<int>(), however, you get the result type of integers comparison which is bool. That is, although there is no subsitution failure, the compiler cannot use the class template specialization, because it is specialized for void, not bool.
In order to fix the code, you should rewrite Enable to always result with void:
template <typename...>
using Enable = void;
This is also known as std::void_t.
Related
Before that I want to tell that I have tried to implement is_assignable on my own. There is no need to show me another examples - I have already seen some implementation.
I would like to fix my solution thanks to you (if it's possible, of course) that'll work out.
So, here is my code:
#include <iostream>
#include <type_traits>
#include <utility>
template<typename LambdaT>
struct is_valid_construction {
is_valid_construction(LambdaT) {}
typedef typename LambdaT lambda_prototype;
template<typename ValueTypeT, typename ExprTypeT = decltype(std::declval<lambda_prototype>()(std::declval<ValueTypeT>()))>
struct evaluate {
evaluate(ValueTypeT val) {
std::cout << "Right!";
}
typedef typename std::true_type value;
};
template<typename ValueTypeT> //The compiler ignores this definition
struct evaluate<ValueTypeT, decltype(std::declval<lambda_prototype>()(std::declval<int>()))> {
evaluate(ValueTypeT val) {
std::cout << "Nope";
}
typedef typename std::false_type value;
};
template<typename ValueTypeT>
void print_value(ValueTypeT val) {
evaluate evaluation(val);
}
};
struct ForTest {};
int main() {
is_valid_construction is_assignable([](auto x) -> decltype(x = x) { });
is_valid_construction is_less_comparable([](auto x) -> decltype(x < x) {});
is_valid_construction is_more_comparable([](auto x) -> decltype(x > x) {});
is_assignable.print_value(int{});
is_less_comparable.print_value(char{});
is_more_comparable.print_value(ForTest{});
return 0;
}
As you can see I am trying to define template structure within template structure. So, I excepted that if the invocation (with declval) of this lambda-expression with parameter of this type (rougly, in terms of substitution) is failed, then SFINAE goes further and should see that the second template definition could be convenient for instantiation. I am asking how could I fix my template structure and its default parameter to push SFINAE use the second definition?
SFINAE can be used in order to direct the compiler to choose a particular function overload, or a particular partial specialization of a class template. In the first case, substitution failures remove declarations from the overload set and in the second case, substitution failures remove the partial specialization declarations from consideration (causing either the primary template to be used, or a different partial specialization for which substitution succeeds).
But what you are trying to do here is backward: you have a situation where the primary template is potentially subject to substitution error, and you provide a partial specialization as an alternative. This can never work. Partial specialization matching begins after the template argument list to the primary template is fully known, therefore if a substitution error occurs in the primary template's template argument list, no specializations can be considered.
For example if we have
template <typename T, typename U = some_metafunction_of_T>
struct S;
template <typename T>
struct S<T, T>;
then the instantiation process of S<int> will first evaluate U for the primary template, and then, only once T and U are both known, the compiler can determine whether or not they are the same (which would allow the partial specialization to be used). If a substitution error occurs while computing U, the question of whether the partial specialization applies cannot even be asked.
To fix your code, you would have to switch the two definitions of evaluate. The primary template would have to be the "fallback", and the partial specialization would have to be potentially subject to substitution error.
as #Brian said, you should put the requirements at the primary template if the requirements are for all specializations, and put other requirements for each specialization at their own declarations:
template<typename T, typename = std::void_t</* global requirements */>>
struct S;
template<typename T>
struct S<T, std::void_t</* requirements for this specialization */>>;
and if you want one of specialization is prior to others, you can add its negative requirements to other specializations:
template<typename T, typename = std::void_t</* global requirements */>>
struct S;
template<typename T>
struct S<T, std::void_t<std::enable_if_t</* conditions for this specialization */>>>;
template<typename T>
struct S<T, std::void_t<std::enable_if_t<!/* conditions for the former specialization */>, /* requirements for this specialization */>>;
for your example, it should be like this:
template<typename Lambda>
struct is_valid_construction{
template<typename T, typename = void>
struct helper : std::false_type{};
template<typename T>
struct helper<T, std::void_t<decltype(std::declval<Lambda>()(std::declval<T>()))>> : std::true_type{};
template<typename V, typename = void>
struct evaluate;
template<typename V>
struct evaluate<V, std::enable_if_t<helper<V>::value>>;
template<typename V>
struct evaluate<V, std::void_t<std::enable_if_t<!helper<V>::value>, decltype(std::declval<Lambda>()(std::declval<int>()))>>;
};
by the way, you can use std::is_invocable to simplify this code:
template<typename Lambda>
struct is_valid_construction{
template<typename V, typename = void>
struct evaluate;
template<typename V>
struct evaluate<V, std::enable_if_t<std::is_invocable_v<Lambda, V>>>;
template<typename V>
struct evaluate<V, std::enable_if_t<!std::is_invocable_v<Lambda, V> && std::is_invocable_v<Lambda, int>>>;
};
Thanks to #RedFog and #Brian I could complete my code and I have got the such result:
#include <iostream>
#include <type_traits>
#include <utility>
template<typename LambdaT>
struct is_valid_construction {
is_valid_construction(LambdaT) {}
typedef LambdaT lambda_prototype;
template<class ValueT, class = void>
struct is_void_t_deducable : std::false_type {};
template<class ValueT>
struct is_void_t_deducable<ValueT,
std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>> : std::true_type {};
template<class ValueT>
bool is_valid_for(ValueT value) {
if constexpr (is_void_t_deducable<ValueT>::value)
return true;
else
return false;
}
};
struct ForTest {};
int main() {
is_valid_construction is_assignable([](auto x) -> decltype(x * x) { });
std::cout << is_assignable.is_valid_for(0) << std::endl;
std::cout << is_assignable.is_valid_for(ForTest{});
return 0;
}
As they both said, that when I had declared template parameter like that:
template<typename ValueTypeT, typename ExprTypeT = decltype(std::declval<lambda_prototype>()(std::declval<ValueTypeT>()))>
the compiler didn't understand what a default value should the second template parameter assign and since both declarations are incompatible.
I am new one in template programming and I can try to explain the solution as simple as possible:
The second template parameter is (if to say not strictly!) should be void. So, the compiler can instantiate the template with second void parameter in two ways by means of first declaration or second declaration.
(It should be said that std::void_t<TemplateParam> becomes void if TemplateParam is well!)
If an instantiation with the second declaration is well, then the
second template parameter is void.
If an instantiation with the first declaration is well, then the
second template parameter is void.
So, we should help compiler to deduce both structures with the second template parameter void. When it tries to instantiate is_valid_for(ForTest{}) first of all it tries to deduce
std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>
but gets substitution error. However, nothing prevents to deduce the second template parameter void in another way and the compilers takes the first declaration.
P.S. I know that this explanation is not good but it may help dummies like me!
Since C++20 concepts aren't standardized yet, I'm using static_assert as a makeshift concept check, to provide helpful error messages if a type requirement isn't met. In this particular case, I have a function which requires that a type is callable before getting its result type:
template <typename F, typename... Args>
void example() {
static_assert(std::is_invocable_v<F, Args...>, "Function must be callable");
using R = std::invoke_result_t<F, Args...>;
// ...
}
In addition, I require that the callable's result must be some kind of std::optional, but I don't know what type the optional will hold, so I need to get that type from it:
using R = // ...
using T = typename R::value_type; // std::optional defines a value_type
However, this will fail if type R doesn't have a value_type, e.g. if it's not a std::optional as expected. I'd like to have a static_assert to check for that first, with another nice error message if the assertion fails.
I could check for an exact type with something like std::is_same_v, but in this case I don't know the exact type. I want to check that R is some instance of std::optional, without specifying which instance it must be.
One way to do that is with a helper trait:
template <typename T>
struct is_optional { static constexpr bool value = false; };
template <typename T>
struct is_optional<std::optional<T>> { static constexpr bool value = true; };
template <typename T>
constexpr bool is_optional_v = is_optional<T>::value;
…and then I can write:
static_assert(is_optional_v<R>, "Function's result must be an optional");
That works, but it seems a little awkward to pollute my namespace with a helper trait just for a one-off check like this. I don't expect to need is_optional anywhere else, though I can imagine possibly ending up with other one-off traits like is_variant or is_pair too.
So I'm wondering: is there a more concise way to do this? Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Following the suggestion by several respondents, I made a re-usable trait:
template <typename T, template <typename...> typename Tpl>
struct is_template_instance : std::false_type { };
template <template <typename...> typename Tpl, typename... Args>
struct is_template_instance<Tpl<Args...>, Tpl> : std::true_type { };
template <typename T, template <typename...> typename Tpl>
constexpr bool is_template_instance_v = is_template_instance<T, Tpl>::value;
…so that I can write:
static_assert(is_template_instance_v<R, std::optional>, "Function's result must be an optional");
This is just as many lines and declarations as the is_optional trait, but it's no longer a one-off; I can use the same trait for checking other kinds of templates (like variants and pairs). So now it feels like a useful addition to my project instead of a kluge.
Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Maybe using implicit deduction guides for std::optional?
I mean... something as
using S = decltype(std::optional{std::declval<R>()});
static_assert( std::is_same_v<R, S>, "R isn't a std::optional" );
Explanation.
When R is std::optional<T> for some T type, std::optional{r} (for an r value of type R) should call the copy constructor and the resulting value should be of the same type R.
Otherwise, the type should be different (std::optional<R>).
The following is a full compiling example.
#include <iostream>
#include <optional>
template <typename T>
bool isOptional ()
{
using U = decltype(std::optional{std::declval<T>()});
return std::is_same_v<T, U>;
}
int main ()
{
std::cout << isOptional<int>() << std::endl; // print 0
std::cout << isOptional<std::optional<int>>() << std::endl; // print 1
}
Anyway, I support the suggestion by super: create a more generic type-traits that receive std::option as template-template argument.
Here is MCVE (uncompilable) :-
#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType>
class GetType{
template <typename C> static Slot<T> check( Slot<T>*);
template <typename> static DefaultType check(...);
public: using type=decltype(check<T>());
};
template<class T,template<class>class Slot,class DefaultType>
using X = typename GetType<T,Slot,DefaultType>::type;
Here is its usage :-
//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int , result:int
using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}
My objective is to create a library typedef X< Param1 ,SlotCustom ,DefaultType> that means as the following pseudo code:-
if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default
How to do it?
Here is a similar question.
The main difference is that X<T> there can be only a bool, and many things are hardcoded.
I am new to template specialization. The solution might be obvious, but I can't find it.
If I understand your question correctly, then your approach can be made to work, for example
template <template <class> class Slot, class DefaultType>
struct GetType
{
template <typename T>
static Slot<T>&& deduce(T&&);
static DefaultType&& deduce(...);
template <typename T>
using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;
live demo here
The problem with your initial attempt was that the call to your check function in the expression for decltype() needed some argument for overload resolution to take place so that the SFINAE magic can happen. My example above relies on std::declval to introduce a dummy argument of the necessary type. Also, note that my helper functions use references rather than passing the types by value directly. This is so that it also works with types that are not copyable. Note that there will be problems if Slot<T> or the DefaultType are reference types themselves. One would have to, e.g., introduce additional wrapper types to deal with that…
Alternatively, you could use partial class template specialization to pick the correct type, for example:
template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
using type = DefaultType;
};
template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
using type = Slot<T>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;
live demo here
The trick here lies in the use of the last template parameter with default argument void. Due to the way the matching of partial class template specializations works (see, e.g., this answer), the specialization will only be picked if Slot<T> is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t (as explained here):
template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
I would like to find out if a type defines a member function with a template argument but the template argument is constrained with SFINAE.
Example I have a type A with a single function foo
struct A{
template<typename T>
std::enable_if<Condition<T>,ReturnType> foo(T t){ ... }
};
Condition is some condition e.g. std::is_pos_v
Right now I'm using boost::hana::is_valid to figure out if a type has a member function like foo() or foo(int) but when with template argument I'm lost.
I would like to write something like this
auto has_foo = hana::is_valid([](auto t) -> delctype(hana::traits::declval(t).foo(???)){});
has_foo(hana::type_c<A>); // <-- I want this to return true
The question is what should I put instead of ??? ?
It is probably impossible for the compiler to "prove" that a type A satisfy: "For every type T which satisfy Condition there is a member function A::foo(T)"
So to make it easier for the compiler, I would be happy to at least "prove" that for a type A holds: "There is a type T such that there is a member function A::foo(T)"
Unfortunately, this is still hard in my example because this would require proving that there is a type which satisfy Condition.
Thus isn't it possible for the purpose of introspection to ignore SFIANE? Then I could pick an arbitrary type and test existence of e.g. A::foo(int).
As stated, there is no facility provided for this kind of introspection short of writing a compiler plugin and walking the AST yourself.
You can certainly use hana::is_valid if you provide a concrete T to make a complete and valid expression.
I provided an additional example that allows providing a "concept" assuming some kind of facility for providing a concrete T for whatever "concept" you put in. This is a bit of a reach though.
#include <boost/hana.hpp>
#include <type_traits>
#include <utility>
namespace hana = boost::hana;
using hana::Sequence;
struct A {
template <typename T>
std::enable_if_t<Sequence<T>::value, void> foo(T) { }
};
struct B {
template <typename T>
void bar(T) { }
};
template <typename T>
auto has_foo_1 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(std::declval<T>())) { });
template <template <typename, typename> typename Concept>
auto declval_concept_impl = int{};
template <>
auto declval_concept_impl<Sequence> = hana::tuple<>{};
template <template <typename, typename> typename Concept>
using declval_concept = std::add_rvalue_reference_t<decltype(declval_concept_impl<Concept>)>;
template <template <typename, typename> typename Concept>
auto has_foo_2 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(declval_concept<Concept>{})) { });
int main() {
A a;
B b;
static_assert( has_foo_1<hana::tuple<>>(a));
static_assert(not has_foo_1<hana::tuple<>>(b));
static_assert( has_foo_2<Sequence>(a));
static_assert(not has_foo_2<Sequence>(b));
}
I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:
template <typename T>
class FXP<T>
{ ... };
template <typename T>
class FXP<unsigned T>
{ ... };
but this does not compile.
I even came across:
std::is_integral
std::is_signed
std::is_unsigned
So, how do I put these in action to define a class that only supports these two variants?
In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:
// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
// default implementation here
};
Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).
template <typename T>
class FXP<T, false> {
// partial specialization when is_unsigned becomes false
};
template <typename T>
class FXP<T, true> {
// partial specialization when is_unsigned becomes true
};
In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).
Here's an example, where the default case gets overridden by a specialized template parameter:
http://coliru.stacked-crooked.com/a/bc761b7b44b0d452
Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).
Good luck!
With an additional template parameter:
#include <iostream>
#include <type_traits>
template <typename T, class X = void>
struct FXP
{
// possibly disallow using this primary template:
// static_assert(not std::is_same<X, X>{},
// "Error: type neither signed nor unsigned");
void print() { std::cout << "non-specialized\n"; }
};
template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{ void print() { std::cout << "signed\n"; } };
template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{ void print() { std::cout << "unsigned\n"; } };
struct foo {};
int main()
{
FXP<foo>().print();
FXP<int>().print();
FXP<unsigned int>().print();
}