A variable template that is true iff a class template would instantiate? - c++

Let's say I have a class template A that has one type template parameter, and a single primary specialization:
template<typename T> struct A {
/*...*/
};
For some T arguments A<T> will instantiate successfully, for others it won't.
Without modifying or extending the definition of A, is it possible to write a bool variable template:
template<typename T>
constexpr bool WorksWithA = /*...*/;
such that WorkWithA<T> is true iff A<T> would instantiate successfully?
Update
Posted this as separate question: Using typename in C++20 requires / concept?
#include <iostream>
template<typename T>
struct A {
using X = typename T::X;
};
template<typename T>
constexpr bool WorksWithA = requires { typename A<T>; };
struct GoodArg {
using X = int;
};
struct BadArg {
};
int main() {
std::cout << WorksWithA<GoodArg> << std::endl;
std::cout << WorksWithA<BadArg> << std::endl;
}
Compiled and run with:
$ clang++ --version
clang version 10.0.0-4ubuntu1
$ clang++ test.cc -std=c++20
$ ./a.out
1
1
This outputs 1 1, expected output is 1 0 ?
What gives?

If I'm understanding this correctly, for SFINAE friendly types, this could be a way:
Match if instantiation is possible:
template<class T>
constexpr auto WorksWithA(int) -> A<T>;
Match if it isn't:
struct no {};
template<class T>
constexpr auto WorksWithA(long) -> no;
Helper:
template<typename T>
inline constexpr bool WorksWithA_v =
not std::is_same_v<no, decltype(WorksWithA<T>(0))>;
Demo
If A isn't SFINAE friendly (as the A in the updated question), you'll have to add the check in WorksWithA. In this case:
template<typename T>
struct A {
using X = typename T::X;
};
template<class T>
constexpr auto WorksWithA(int) -> typename T::X;
struct no {};
template<class T>
constexpr auto WorksWithA(long) -> no;
template<typename T>
inline constexpr bool WorksWithA_v =
not std::is_same_v<no, decltype(WorksWithA<T>(0))>;
Demo

You misunderstand how templates work.
template<typename T>
struct A {
using X = typename T::X;
};
template<typename T>
constexpr bool WorksWithA = requires { typename A<T>; };
struct GoodArg {
using X = int;
};
struct BadArg {
};
BadArg fundamentally works with A. It isn't bad.
template<typename T>
struct A {
using X = typename T::X;
};
this does not require that T have a typename X.
This states that if it does have a typename X, then A::X is that typename.
So WorksWithA does test correctly if T can instantiate the template A.
This doesn't help you directly, but understanding that you are asking the wrong question is important, and why your question is the wrong one. Because that leads to the right question.
Either you want A not not instantiate when T does not have a type X, or you want WorksWithA to do a different kind of test.
For example, maybe you want HasAnX:
template<class T>
concept HasAnX = requires { typename T::X; };
then
static_assert(HasAnX<GoodArg>);
static_assert(!HasAnX<BadArg>);
compiles.
However, I'd guess that semantically this doesn't match what you want it to match. You want it to be the A-ness not the X-ness you are measuring.
Then your problem is probably not with WorksWithA, but with A itself. You thought you where adding a requirement that T HasAnX, but you where not.
template<HasAnX T>
struct A {
using X = typename T::X;
};
that makes A require that T has an X. Now, WorksWithA ... works as you intended.
Live example.

This is a good (and right) question, but I think as up until now there is no answer for this question in general.
Lets assume the class template A is simply like:
template<typename T>
class A{
public:
T variable;
}
This template works with most of types but it does not instantiate with T = void for the obvious reason. now lets assume we want to find that out before hand with a SFINAE friendly method.
The best tool to find out if a type is instantiatable is to check whether it has a size, now Lets define a tool similar to std::void_t:
template<size_t...> using void_size_t = void;
now if we define:
template< class, class = void >
struct pre_WorksWithA : std::false_type { };
template< class T >
struct pre_WorksWithA<T, void_size_t<sizeof(A<T>)>> : std::true_type { };
template<typename T>
constexpr bool WorksWithA = pre_WorksWithA<T>::value;
In case of a normal types like int the result is true which it should be. but in case of void neither the WorksWithA nor pre_WorksWithA can instantiate and the result would be an error from the compiler.
So as you can see, up until now, basically there is no feature in C++ to help us know whether a type is instantiate-able or not without giving an error?

You can use a simple concept:
template<typename T>
constexpr bool WorksWithA = requires { typename A<T>; };

Related

Extracting the underlying type in the template

I am new to C++20. The intention here is to have a template class which has value whose type would be the underlying type of T that's passed in.
So in case of T being:
std::optional<char>, it's char value
int, it's just int value.
Is there any better way to extract the types than through struct TypeExtract? More or a generic solution in C++20 perhaps? Given if the class could take more than just std::optional<int> or just a primitive type?
Can the condition in foo be improved specially with the way val is initialized?
template<typename T>
constexpr bool is_optional = false;
template<typename T>
constexpr bool is_optional<std::optional<T>> = true;
template<typename T>
struct TypeExtract
{
using type = T;
};
template<typename T>
struct TypeExtract<std::optional<T>>
{
using type = T;
};
template <typename T>
concept is_integral = std::is_integral_v<typename TypeExtract<T>::type>;
template <is_integral T>
class A
{
using Type = typename TypeExtract<T>::type;
Type val;
void foo(T value)
{
if constexpr (is_optional<T>)
{
val = *value;
}
else
{
val = value;
}
}
};
int main()
{
A<char> a1;
A<std::optional<int>> a2;
// A<double> a3; // fails
}
It looks like you're trying to extract first template parameter from a class template and keep on unwinding templates until you get to a non-template type. In that case you could make a type trait that is specialized for types instantiated from templates:
// primary template
template<class T, class...>
struct type {
using value_type = T;
};
// specialization for template instantiated types
template<template<class, class...> class T, class F, class... Rest>
struct type<T<F, Rest...>> {
using value_type = typename type<F>::value_type;
};
// helper alias
template<class... Ts>
using type_t = typename type<Ts...>::value_type;
You could then use it like so:
int main() {
type_t<char> a1;
type_t<std::optional<int>> a2;
type_t<double, int> a3;
static_assert(std::is_same_v<decltype(a1), char>);
static_assert(std::is_same_v<decltype(a2), int>);
static_assert(std::is_same_v<decltype(a3), double>);
}
There is no good or bad here, it's a matter of style and convention, but personally I would get rid of if constexpr and take advantage of trailing requires for the sake of reducing function's cyclomatic complexity. On the other hand, that add some boilerplate. The choice is yours.
Not much can be done about type extraction, though I would probably use a templated base and import its member(s) instead of importing the type into the class. Not a big deal, but it feels more idiomatic to me.
As for concepts, I'd probably use more library-provided ones in the place of type traits.
Side note: consider using assert, .value() or similar function when assigning from the optional to ensure it's not empty.
All in all, I'd probably write your code somewhat this way:
#include <concepts>
#include <type_traits>
#include <optional>
template<typename T>
concept StdOptional = std::same_as<std::optional<typename T::value_type>, T>;
template<typename T>
concept OptionalIntegral = StdOptional<T> and std::integral<typename T::value_type>;
template<typename T>
concept OptionalOrOptionalIntegral = std::integral<T> or OptionalIntegral<T>;
template<typename>
struct ABase;
template<std::integral T>
struct ABase<T>
{
T value;
};
template<OptionalIntegral T>
struct ABase<T>
{
typename T::value_type value;
};
template<OptionalOrOptionalIntegral T>
class A : ABase<T>
{
using ABase<T>::value;
public:
void setValue(T val) requires(std::integral<T>)
{
value = val;
}
void setValue(T val) requires(OptionalIntegral<T>)
{
value = val.value();
}
};
Demo: https://godbolt.org/z/dzvr9xbGr

Check the existence of a template function

How can I check the existence of a template function like this: Checking if reader struct has read arithmetic value
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
I use a checker like this:
template <typename T>
struct test_read {
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
};
But the compiler complains:
error: wrong number of template arguments (1, should be 2)
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
Please give me your advice on that.
Thank you.
Update: Here is the final version I got after discussion, I hope everyone will find it helpful for your code
struct not_reader {
};
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
template<class T, class Elem>
struct has_read {
private:
template<class C, typename=void>
struct test_read : std::false_type {
};
template<class C>
struct test_read<C, typename std::enable_if<std::is_convertible<decltype(std::declval<C>().template read<Elem>()), Elem>::value>::type>
: std::true_type {
};
public:
using type = typename test_read<T>::type;
static constexpr bool value = test_read<T>::value;
};
static_assert(has_read<reader, int>::value, "reader should have int read()");
static_assert(!has_read<not_reader, int>::value, "not_reader should not have int read()");
You forgot template before read()
static constexpr auto value
= std::is_convertible<
decltype(std::declval<T>().template read<int>()),int>::value;
// .................................#########
But I don't think that your code can check " if reader struct has read arithmetic value": try calling test_read with type int and you should get a compilation error.
The following is an example of an alternative solution
#include <type_traits>
struct reader
{
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read()
{ return {}; }
};
template <typename, typename = void>
struct readTypeRet
{ using type = void; };
template <typename T>
struct readTypeRet<T, decltype(std::declval<T>().template read<int>(), void())>
{ using type = decltype(std::declval<T>().template read<int>()); };
template <typename T>
struct test_read
: public std::is_convertible<typename readTypeRet<T>::type, int>
{ };
int main ()
{
static_assert(test_read<reader>::value == true, "!");
static_assert(test_read<int>::value == false, "!");
}
To briefly restate your problem in terms that are a bit clearer:
You have some function that will return T if T satisfies is_arithmetic, otherwise it returns void
You want to assert that calling this function with int will return a type convertible to int
I think the shortest path to fix your code is to take advantage of std::result_of (C++11/14, use std::invoke_result_t in C++17):
template<class T>
struct test_read {
static constexpr auto value = std::is_convertible<
typename std::result_of<decltype(&T::template read<int>)(T)>::type, int
>::value;
};
Live Demo
Some notes about this solution:
When specifying the read member function of T (reader), we need to use the template keyword to inform the compiler that the name reader is a template.
Use of result_of requires a function-like syntax of F(Args), so here we are getting the type of reader::read as the F portion, and then passing reader as the Args portion
we must pass an instance of T (reader) to read because it is a member function (rather than static or free), and member functions implicitly take a reference to the instance of the class they're being called on.

Specializing function template for templated derived class

I essentially have a mock version of std::integral_constant that includes a variable and I want to specialize a function template for these classes derived from Base<T>, like this:
template<class T> struct Base{
typedef T type;
T t;
};
template<class T> struct A : Base<T>{
static constexpr T value = 1;
};
template<class T> struct B : Base<T>{
static constexpr T value = 2;
};
struct Unrelated{};
// etc.
template<class T> void foo(T t){
//I would like to specialize foo for A and B and have a version for other types
}
int main(){
foo(A<float>());//do something special based on value fields of A and B
foo(B<float>());
foo(Unrelated()); //do some default behavior
}
Here are the main issues:
I cannot include value as a template as I am expecting T = double, float, or some other non-integral types (otherwise I'd just extend std::integral_constant)
I can't cleanly use std::is_base as I would have to do std::is_base<Base<T::type>,T>
Doing foo(Base<T>&) wouldn't allow me to see value and I don't want to have to resort to a virtual value() function (or reflection).
And obviously I would like to avoid specializing foo for every derived class.
I think the answer lies in using is_base but I haven't been able to get it to work no matter how I tried to use it. Is there a much simpler way I am missing?
The following should work:
template<typename,typename = void>
struct IsBase
: std::false_type {};
template<typename T>
struct IsBase<T, typename std::enable_if<
std::is_base_of<Base<typename T::type>,T>::value
>::type>
: std::true_type {};
template<class T>
typename std::enable_if<IsBase<T>::value>::type foo(T t){
// use T::value
}
template<class T>
typename std::enable_if<!IsBase<T>::value>::type foo(T t){
// general case
}
Live example

Is there a way a partial specialization is always preferred over the primary template?

I'm asking myself
Can you write a class template and a corresponding partial specialization such that for any set of template arguments for the parameters, the partial specialization is taken by the compiler?
For example
template<typename T>
struct A { };
template<typename T>
struct A</* what to write!?*/> { };
I seem to remember having read that this is possible somehow, but I forgot the exact algorithm to make this work.
My version of GCC is happy to accept:
template<typename T>
struct A;
template<typename... Pack>
struct A<Pack...> {};
If you allow SFINAE trick then, it will be as easy as this:
enum E { TRUE };
template<typename T, E = TRUE>
struct A
{
static const bool value = false;
};
template<typename T>
struct A<T, TRUE>
{
static const bool value = true;
};
Demo.

SFINAE approach comparison

The following code shows an SFINAE implementation to check whether a type (basically a class) contains a member function member_func at compile time.
#define CHECKER(func_name,class_name) sizeof(class_name<T>::template func_name<T>(0)) == 1
#include <iostream>
struct A
{
void member_func();
};
struct B {};
template<typename T>struct Check_If_T_Is_Class_Type
{
template<typename C> static char func (char C::*p);
template<typename C> static long func (...);
enum{val = CHECKER(func,Check_If_T_Is_Class_Type)};
};
//APPROACH 1
template <typename T>struct TypeHasMemberFunc
{
template <typename C, C> struct TypeCheck;
template <typename C> struct Prototype_Holder {typedef void (C::*fptr)();};
template <typename C> static char func(TypeCheck
<
typename Prototype_Holder<C>::fptr,
&C::member_func
>*);
template <typename C> static long func(...);
enum {value = CHECKER(func,TypeHasMemberFunc)};
};
//APPROACH 2
template <typename T>struct has_member_func
{
template<class C> static char func(char (*)[sizeof(&C::member_func)]);
template<class C> static long func(...);
enum{value = CHECKER(func,has_member_func)};
};
int main(){
if(Check_If_T_Is_Class_Type<A>::val)
std::cout<<TypeHasMemberFunc<A>::value; //using APPROACH 1
if(Check_If_T_Is_Class_Type<B>::val)
std::cout<<has_member_func<B>::value; //using APPROACH 2
}
However my question is which approach would you prefer (APPROACH 1 or APPROACH 2) and why?
Do you find any inconsistency in the given approaches? If yes please let me know.
P.S : Assume sizeof(char)!= sizeof(long)
Second approach doesn't check function type (return type or arguments types) and does work with all types, not only class types.
I would personally prefer the second approach to play with as it is shorter and easier to understand. But GCC won't compile it, so you have to use something like that for GCC:
namespace detail
{
template<class C> char func(char (*)[sizeof(&C::member_func)]);
template<class C> long func(...);
}
template <typename T>struct has_member_func
{
enum{value = (sizeof(detail::func<T>(0)) == 1)};
};
Also, It would be nice to get rid of CHECKER macro. It makes your code extremely less readable.
Anyway, I would refrain from using such C++ hacks in production code (except you are a Boost team member :-)
Such stuff is error-prone, hard to support, hardly portable between compilers but the principal point is that I do not remember any real life task demanded such hard-code C++.
EDIT: completed and corrected.
Another approach, using ambiguity from inheritance, probably functionally equivalent to your Approach 2. I remember having problems with Approach 1 (it compiles with G++ 4.4.5 though) because the name resolution triggered an error and not a substitution failure. I had to resort to:
template <class T>
struct has_foo
{
struct fallback { void foo(...); };
struct D : T, fallback { };
template <typename U, U> struct K;
// Will be ambiguous for U = D iff T has a foo member function.
// It doesn't trigger an error, since D will always have at least one
// foo member function.
template <class U> static char (&test(K<void (fallback::*)(...), &U::foo>*))[1];
template <class U> static char (&test(...))[2];
static const bool value = sizeof(test<D>(0)) == 2;
};
This works when T is a class, so you may want to add your layer for checking whether T is a class type.
Note that any foo member function will be detected. If you want to check whether the detected foo function can be called with given arguments, you have to do another layer of SFINAE:
// Check whether foo can be called with an argument of type Arg
// and yields an element of type Res.
// If you need Res = void, this code does not work.
template <class T, typename Arg, typename Res>
struct check_foo
{
struct flag {};
struct D : T { using T::foo; flag foo(...); };
template <typename U>
static char (&test(U))[1];
template <typename> static char (&test(...))[2];
static Arg f();
static const bool value = sizeof(test<Arg>( ((D*)0)->foo(f()) )) == 1;
};