How to use a trait type as an argument to an optionally compiled member function of a class template? - g++

I would like to define a member function in a class template only if traits contain type and use type as its argument like that:
struct A {};
struct B { using type = int; };
template <typename T>
concept has_type = requires { typename T::type; };
template <typename Traits>
struct Handler
{
void set(typename Traits::type)
requires has_type<Traits>
{}
};
Unfortunately, typename Traits::type is parsed before the requires clause and it fails to compile if type does not exist (struct A):
<source>:19:14: error: no type named 'type' in 'struct A'
19 | void set(typename Traits::type)
I could only come up with this alternative, which looks excessively cumbersome:
template <typename Traits>
struct Handler
{
template <typename Type>
requires has_type<Traits> && std::same_as<Type, typename Traits::type>
void set(Type)
{}
};
It also fails to compile under clang (although I expected it to short-circuit), but gcc compiles it correctly:
<source>:20:78: error: no type named 'type' in 'A'
requires has_type<Traits> && std::same_as<Type, typename Traits::type>
Full example.
Questions
What is the idiomatic way to define set depending on whether Traits class contains type?
Why does clang try to evaluate std::same_as if requires has_type failed?
Who is right, clang or gcc?

A class template member function is constrainable, but is not SFINAE-aware. The idiomatic solution (which, inter alia, works even under C++17) is to make set a (class template member) function template accessing the type member type alias via (type-dependent) SFINAE context:
template<int..., class U = Traits>
void set(typename U::type);
or:
template<std::same_as<Traits> U = Traits>
void set(typename U::type);
Example.
wrt 2., 3., see How to use a trait type as an argument to an optionally compiled member function of a class template?

Related

Test to detect if a template type in C++/CLI is managed or unmanaged

I have some template code compiled with /clr, something like the following
template <typename T> void foo( )
{
}
and am wondering if it's possible to detect if the T is a managed type or an unmanaged one. So something like
template <typename T> void foo( )
{
constexpr bool b = is_managed_type<T>;
}
If have tried all the std library type traits and those mentioned here https://learn.microsoft.com/en-us/cpp/extensions/compiler-support-for-type-traits-cpp-component-extensions?view=vs-2019 but have not found anything that works in all cases. A particular instance of this problem is to tell if an enum is a managed enum or an unmanaged one. So is it possible to implement a type trait like this?
Added 9/23/19
I did make some progress on a is_managed_type trait. I have the following
int check( System::Object^ );
template <typename T, typename U = void> using converts_to_system_object_t = decltype(check(std::declval<T>()));
template<typename T, typename = void> struct is_managed_type: std::false_type {};
template<typename T> struct is_managed_type<T, converts_to_system_object_t<T>> : std::true_type { };
The basic idea is to test if for given type can you call a function that takes os System::Object^. Note I did try things like std::is_base_of and std::is_convertible but they all had problems.
However this seem to return false for managed enums which is a bit bizzare to me

Create the following Generic IEnumerable in CLI/C++?

how is it possible to create the following Generic IEnumerable in CLI/C++:
IEnumerable<T> Fetch<T>() where T: MyFetch, new() { }
I tried some stuff around, but didn't found a solution that looks 'legit' and fits my needs.
I want the function to be part of a class
You don't use the ^ hat in the where clause. It names a type, not a handle to the type as you'd use for a variable or parameter declaration. The T type parameter is already introduced by the generic keyword, you don't apply it again to the method name like you'd do in C#. It should therefore look like this:
generic <typename T>
where T: MyFetch, gcnew()
IEnumerable<T>^ Fetch() {
// etc...
}
This would be a generic function in your ref class, and would look similar to:
generic <typename T>
where T: MyFetch, gcnew()
IEnumerable<T>^ Fetch()
{
}

Access method of extended type in Go

The follow codes produces "prog.go:17: c.Test undefined (type Child has no field or method Test)". (http://play.golang.org/p/g3InujEX9W)
package main
import "fmt"
type Base struct {
X int
}
func (b Base) Test() int {
return b.X
}
type Child Base
func main() {
c := Child{4}
fmt.Println(c.Test())
}
I realize Test is technically defined on Base, but should Child inherit that method?
the way to go for inheritance in go is using struct embedding with anonymous struct members.
Here is an adaption of your example.
Read about struct embedding and go's approach to inheritance etc here
The behaviour you encountered is expected and in sync with the golang specification, which explicitly states that:
The method set of any type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set.

Obj-C++: template metafunction for recognizing Objective-C classes?

Using Objective-C++, can I write a C++ IsObjectiveCClass<T> template metafunction such that IsObjectiveCClass<T>::value is true if and only if T is an Objective-C class?
Exactly what are ObjC classes from the viewpoint of the C / C++ subset of the language? When used in a C / C++ context, MyClass* pointers seem to behave like ordinary C pointers; does that mean that MyClass is also a C type?
Here is a simplistic solution that should work in most (if not all? Can anyone think of when this might fail?) cases (it uses clang 3.0 via xcode 4.2 - use typedefs instead of using aliases for earlier clang versions):
template<class T> struct IsObjectiveCClass
{
using yesT = char (&)[10];
using noT = char (&)[1];
static yesT choose(id);
static noT choose(...);
static T make();
enum { value = sizeof(choose(make())) == sizeof(yesT) };
};
You can read my most recent rant about ObjC++ in this question. Avoid it as much as you can possibly get away with. Definitely don't try to integrate Objective-C into C++ template metaprogramming. The compiler might actually rip a hole in space.
Hyperbole aside, what you're trying to do is likely impossible. Objective-C classes are just structs. (C++ classes actually just structs too.) There's not much compile-time introspection available.
An id is a C pointer to a struct objc_object. At runtime, every object is an id, no matter its class.
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
As with the accepted answer, you can test whether the type is convertible to id, in C++17:
template <typename T>
struct is_objc_ptr : std::integral_constant<bool,
std::is_convertible_v<T, id> && !std::is_null_pointer_v<T>> {};
template <typename T>
constexpr bool is_objc_ptr_v = is_objc_ptr<T>::value;
Testing:
static_assert(!is_objc_ptr_v<nullptr_t>);
static_assert(!is_objc_ptr_v<int>);
static_assert(!is_objc_ptr_v<char *>);
static_assert(is_objc_ptr_v<id>);
static_assert(is_objc_ptr_v<NSObject *>);
I don't know of a way to discover ObjC inheritance relationships at compile-time; in theory they're changeable at runtime so you would have to query the runtime.
If you look at the implementation of the C++ STL library in Xcode, you can follow the template specialization models of others like std::is_integral or std::is_floating_point:
template <class T> struct isObjcObject : public std::false_type { };
template <> struct isObjcObject<id> : public std::true_type { };
where std::false_type and std::true_type are defined in the <type_traits> header file.
If for whatever reason you don't have std::false_type and std::true_type (depending on your C++ version), you can define them yourself as such:
template<bool B> struct boolean_constant { static constexpr const bool value = B; };
template <class T> struct isObjcObject : public boolean_constant<false> { };
template <> struct isObjcObject<id> : public boolean_constant<true> { };
Note that you can also do this for Objective-C classes too:
template <class T> struct isObjcClass : public std::false_type { };
template <> struct isObjcClass<Class> : public std::true_type { };
I would create a template specialisation for 'id' and 'NSObject*', but you'll always be working against the language because the ObjC type system is not the C++ type system.
Similar to Doug's answer, but slightly simpler:
template<typename T>
inline constexpr bool is_objc_v = std::is_convertible_v<id,T>;
Checking that id is convertible to T – instead of the other way around – avoids false positives for C++ types which have a user-defined implicit conversion to an Obj-C type.

Mixins, variadic templates, and CRTP in C++

Here's the scenario: I'd like to have a host class that can have a variable number of mixins (not too hard with variadic templates--see for example http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.144). However, I'd also like the mixins to be parameterized by the host class, so that they can refer to its public types (using the CRTP idiom).
The problem arises when trying to mix the two--the correct syntax is unclear to me.
For example, the following code fails to compile with g++ 4.4.1:
template <template<class> class... Mixins>
class Host : public Mixins<Host<Mixins>>... {
public:
template <class... Args>
Host(Args&&... args) : Mixins<Host>(std::forward<Args>(args))... {}
};
template <class Host> struct Mix1 {};
template <class Host> struct Mix2 {};
typedef Host<Mix1, Mix2> TopHost;
TopHost *th = new TopHost(Mix1<TopHost>(), Mix2<TopHost>());
With the error:
tst.cpp: In constructor ‘Host<Mixins>::Host(Args&& ...) [with Args = Mix1<Host<Mix1, Mix2> >, Mix2<Host<Mix1, Mix2> >, Mixins = Mix1, Mix2]’:
tst.cpp:33: instantiated from here
tst.cpp:18: error: type ‘Mix1<Host<Mix1, Mix2> >’ is not a direct base of ‘Host<Mix1, Mix2>’
tst.cpp:18: error: type ‘Mix2<Host<Mix1, Mix2> >’ is not a direct base of ‘Host<Mix1, Mix2>’
Does anyone have successful experience mixing variadic templates with CRTP?
The following seems to work. I added Mixins... in the inherited mixin classes which expands the parameter pack inplace. Outside the body of Host template, all template parameters of Host must be specified so Mixins... serves the purpose. Inside the body, just Host is sufficient no need to spell out all its template parameters. Kind of a short hand.
#include <utility>
template <template<class> class... Mixins>
class Host : public Mixins<Host<Mixins...>>...
{
public:
Host(Mixins<Host>&&... args) : Mixins<Host>(std::forward<Mixins<Host>>(args))... {}
};
template <class Host> struct Mix1 {};
template <class Host> struct Mix2 {};
int main (void)
{
typedef Host<Mix1, Mix2> TopHost;
delete new TopHost(Mix1<TopHost>(), Mix2<TopHost>());
}