I'm learning how to use SFINAE to my advantage. I'm trying to use it to select the function implementation based on existence of a serialize() function in an object.
This is the code I use to determine, if the type defines the serialize() function:
template <typename T>
class HasSerialize {
private:
typedef char yes[1];
typedef char no[2];
template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;
template <typename C> static no& test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
However, it seems to give exactly oposite results on GCC and on Clang. Assume the following code:
template<bool T>
class NVPtypeSerializer {
public:
template<typename C>
static xmlChar* serialize(C value) {
// serize() is not available
}
};
template<>
struct NVPtypeSerializer<true> {
public:
template<typename T>
static xmlChar* serialize(T value) {
return value.serialize();
}
};
Which is called like this:
foo = NVPtypeSerializer<HasSerialize<Bar>::value >::serialize(value);
Where the class Bar doesn't have the serialize() function. This code compiles fine under Clang 3.1, however on GCC 4.7.1 I get the following errors:
error: ‘class Bar’ has no member named ‘serialize’
If I change the struct NVPtypeSerializer<true> to struct NVPtypeSerializer<false> it can be compiled on GCC, but Clang gives the following error:
error: no member named 'serialize' in 'Bar'
Where is the problem? Is it in my code? I'd like to have the code portable as much as possible.
Is this really the code test(char[sizeof(&C::serialize)])? Note that a declaration of a function that takes an array actually declares a function that takes a pointer:
template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;
That actually means:
template <typename C> static yes& test( char* );
Which incidentally is what makes your call test<C>(0) compile. I don't think that is the proper way of detecting whether the function exists or not. Google on how to detect whether a member/member function exists in a class using SFINAE.
(A simple solution would be adding an extra defaulted argument --provided that you have a C++11 enabled compiler:
template <typename C, std::size_t = sizeof(&C::serialize)>
static yes& test(int) ;
)
Related
I want to write a concept that checks if the type has a static method called foo. That method will have a templated parameter (the function will be called multiple times later with different parameter types).
Because of that templated parameter, it's quite difficult to check it. For the start, I thought I only check if there is a member at all with that name.
The following code compiles with Clang, but doesn't compile with GCC, because it cannot resolve the address of the overloaded function T::foo.
template <typename T>
concept HasFoo = requires { T::foo; };
class Bar {
public:
template <typename T>
static void foo(T t);
};
static_assert(HasFoo<Bar>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)?
And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
One way would be to include the templated type into the concept, but as I want to use the method with multiple different types.
So checking with only one type, like in the following code, is not enough.
template <typename T, typename T2>
concept HasFoo = requires { T::template foo<T2>; };
static_assert(HasFoo<Bar, int>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)? And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
I do have some constraints on template arguments, for the sake of the simplified example in the question we can just assume it's an integer type.
To check if the class support a static template method foo() that is callable with an integer and return void, you can simply check
template <typename T>
concept HasFoo = std::is_same_v<decltype(T::foo(0)), void>;
If you also want to be sure that the foo() method is a template one, I suppose you can also check that converting &T::foo to different function pointer types you get different values, so (for example)
( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
Combining the two requirements,
template <typename T>
concept HasFoo = ( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
&& std::is_same_v<decltype(T::foo(0)), void>;
With
struct Bar1
{ template <typename T> static void foo (T) {} };
struct Bar2
{ static void foo (int) {} };
struct Bar3
{ template <typename T> static T foo; };
template <typename T>
T Bar3::foo;
struct Bar4
{ template <typename T> static int foo (T) { return 0; } };
you have
static_assert(HasFoo<Bar1>);
static_assert(not HasFoo<Bar2>); // not because foo() isn't template
static_assert(not HasFoo<Bar3>); // not because foo isn't callable
static_assert(not HasFoo<Bar4>); // not becasue foo() return int
I have come across such syntax:
template<typename>
struct is_const{static const bool value = 0;};
How will this code behave and how could it be applied? I didn't find any example or explanation in the Internet.
I am wondering about lack of the argument name (e.g. T).
This is a primary template which takes a single template argument and has a static bool member equal to 0. It is likely that this is the primary template definition for a type trait and that there is a corresponding specialization elsewhere which looks like this:
template <typename T>
struct is_const<const T>
{static const bool value = 1;};
This would allow you to check if a type is const qualified like so:
static_assert(!is_const<int>::value, "wat");
static_assert(is_const<const int>::value, "wat");
template <typename T>
class SampleClass
{
public:
T values [2];
SampleClass(T first, T second)
{
values[0]=first;
values[1]=second;
}
};
Try Something like this typename are generic way of programming. search for generic programming c++. You will get alot of resources
On a basic level of explanation, each time the template is used the compiler generates a version of the templated struct, class, function, etc.
for example:
template<typename T>
struct StructName
{
T memberVariable;
};
when this code is used:
StructName<float> variable = StructName<float>();
the compiler generates:
struct StructName
{
float memberVariable;
};
you can read more about this here: https://en.wikipedia.org/wiki/Template_metaprogramming
I already have SFINAE code that detects whether a given member function exists AND can accept an instance of a specific type.
I'm trying to detect when there's a specific member function that takes as it's argument a NON-REFERENCE.
Example code
template<typename TYPE_T>
class HasSwapMemberImpl
{
/*
* This uses the compilers type deduction magic to ensure that there's SOME swap function
* that's a member of CLASS_T, that can be passed an instance of CLASS_T, in some fashion.
* This doesn't determine that the argument for the function is a reference.
*/
template <typename CLASS_T>
static auto test_compatible_swap_function_exists(CLASS_T * p) -> decltype(p->swap(*static_cast<CLASS_T*>(nullptr)), boost::true_type());
/*
* If no substitutions can satisfy p->swap(*static_cast<CLASS_T*>(nullptr)
* we end up here as fallback.
*/
template<typename>
static boost::false_type test_compatible_swap_function_exists(...);
public:
typedef decltype(test_compatible_swap_function_exists<TYPE_T>(nullptr)) type;
static const bool value = type::value;
};
/**
* \brief This MetaProgramming helper class determines if there exists a method named "swap" in the ARG_T type, that takes ARG_T as an argument.
*
* If ARG_T.swap(ARG_T) is a valid function, then HasSwapMember inherits from boost::true_type. Else it inherits from boost::false_type.
*/
template<typename ARG_T>
struct HasSwapMember : public HasSwapMemberImpl<ARG_T>::type { };
This works for several dozen test cases that I've written, so I'm not in need of any assistance here.
Instead, what I'm trying to do is detect a situation like this
struct NonReferenceSwap
{
void swap(NonReferenceSwap) {}
};
struct ReferenceSwap
{
void swap(ReferenceSwap &) {}
};
I want some metaprogramming helper, MetaHelperType, such that MetaHelperType inherits from boost::true_type, but MetaHelperType causes the compiler to error out with a message like "Swap functions must take reference arguments!"
Or, in other words:
MetaHelperType<ReferenceSwap>; // IS A boost::true_type
MetaHelperType<NoSwapFunction>; // IS A boost::false_type
MetaHelperType<NonReferenceSwap>; // Compiler error
Why do I want this? It's a nonsense concept to try to call foo.swap(bar), when bar will be passed as a value. My organization has a lot of novice c++ programmers, and we want to be able to catch this mistake immediately, and not find out someone forgot the & 2 months later.
I'm using Visual Studio 2010, so not all c++11 features are available. The code above does work properly though, so at least those features work as expected.
Is this possible? If so, what minimum version of C++ is needed? C++11, C++14, C++17?
I use the following for exact signature check:
#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_ref_swap, T::swap, void (T::*)(T&));
DEFINE_HAS_SIGNATURE(has_value_swap, T::swap, void (T::*)(T));
And then, you can write your helper check:
template <typename T>
struct MetaHelperType_impl
{
static_assert(!has_value_swap<T>::value,
"Incorrect implementation of T::swap, "
"signature should be void T::swap(T&) instead of T::swap(T)");
using type = std::conditional_t<has_ref_swap<T>::value,
boost::true_type,
boost::false_type>;
};
template <typename T>
using MetaHelperType = typename MetaHelperType_impl<T>::type;
Demo
Get swap's member function pointer and cast it into the proper signature you're expecting. Together with enable_if you can check if this cast fails or not:
template <typename T>
struct swap_signature { typedef void(T::*type)(T&); };
template <typename T, typename = void>
struct is_swappable : std::false_type {};
template <typename T>
struct is_swappable<T,typename std::enable_if<std::is_member_function_pointer<
decltype(static_cast<typename swap_signature<T>::type>(&T::swap))>::value>::type> : std::true_type {};
Then you can test:
is_swappable<ReferenceSwap>::value // true
is_swappable<NonReferenceSwap>::value // false
I've written my attempt at a C++03-compatible implementation of is_default_constructible:
template<class = void> struct is_default_constructible;
template<> struct is_default_constructible<>
{
protected:
// Put base typedefs here to avoid pollution
struct twoc { char a, b; };
template<bool> struct test { typedef char type; };
template<class T> static T declval();
};
template<> struct is_default_constructible<>::test<true> { typedef twoc type; };
template<class T> struct is_default_constructible : is_default_constructible<>
{
private:
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U*);
template<class U> static char sfinae(...);
public:
static bool const value = sizeof(sfinae<T>(0)) > 1;
};
When I test it in GCC (-std=c++03), it returns 0 because the constructor is invisible:
class Test { Test(); };
int main()
{
return is_default_constructible<Test>::value;
}
When I test it in Visual C++ (different versions all have the same behavior), I get back 1.
And when I test it in Clang (also -std=c++03), I get:
error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
^
note: while substituting explicitly-specified template arguments into function template 'sfinae'
static bool const value = sizeof(sfinae<T>(0)) > 1;
^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;
^
error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
^
note: while substituting deduced template arguments into function template 'sfinae' [with U = Test]
static bool const value = sizeof(sfinae<T>(0)) > 1;
^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;
Which compiler is correct and why?
The code is not valid C++03, although it is valid C++11. The g++ 4.8 compiler is abiding to the C++11 rules and ignoring inaccessible members in an SFINAE context, while clang compilers is abiding to the C++03 where the member (constructor in this case) is found and selected, but access checks make the code invalid. VS (whatever version you are using) is not abiding to C++11 or C++03 rules, it seems to be ignoring the access specifier inside the sizeof completely.
I'm working with some SFINAE features; currently in a portion of an application that must run in Linux and Windows; the compiler choices are MSVC (Visual Studio 2010 10.0) for Windows applications and GCC 4.4.5 for the Linux ones.
I must check if some given object provides some functions to perform a custom serialization and call this functions, or do a simple memcpy and sizeof(Object) while the custom serialization methods are not provided.
The problem is that a piece of code compile without warnings nor errors in MSVC but while compiling with GCC, the code is the following:
template
<
typename Type,
typename Return,
typename Parameter,
Return (Type::*Pointer)(Parameter) const
> struct sMemberMethodConst { };
template
<
typename Type,
typename Return,
typename Parameter,
Return (Type::*)(Parameter)
> struct sMemberMethod { };
template<typename T> struct sMemberMethodChecker
{
template <typename Type> static char HasCustomSizeMethod(sMemberMethodConst<Type, size_t, void, &Type::Size> *);
template <typename Type> static long HasCustomSizeMethod(...);
template <typename Type> static char HasSerializeMethod(sMemberMethodConst<Type, size_t, void * const, &Type::Serialize> *);
template <typename Type> static long HasSerializeMethod(...);
template <typename Type> static char HasDeserializeMethod(sMemberMethod<Type, size_t, const void * const, &Type::Deserialize> *);
template <typename Type> static long HasDeserializeMethod(...);
// Other specific method checks...
enum
{
HAS_CUSTOM_SIZE_METHOD = (sizeof(HasCustomSizeMethod<T>(0)) == sizeof(char)),
HAS_SERIALIZE_METHOD = (sizeof(HasSerializeMethod<T>(0)) == sizeof(char)),
HAS_DESERIALIZE_METHOD = (sizeof(HasDeserializeMethod<T>(0)) == sizeof(char)),
IS_CUSTOM = HAS_CUSTOM_SIZE_METHOD &&
HAS_SERIALIZE_METHOD &&
HAS_DESERIALIZE_METHOD,
// Other 'shortcuts'...
};
And the error that I'm getting while compiling with GCC is:
invalid parameter type 'void' in declaration template<class Type, class Return, class Parameter, Return (Type::* Pointer)(Parameter)const>
in the first line of the struct sMemberMethodChecker. I'm quite sure that I'm don't missing typenames nor misplacing words but I don't understand why I'm getting the error and doesn't understand the error.
I know that the MSVC is lax with standard while GCC conforms the standard pretty well so I'm wondering if the problem lies into the MSVC side that allows silly code!
Here are the questions:
Why am I getting the invalid parameter type 'void' error in the struct sMemberMethodChecker?.
Why the code is valid in MSVC but invalid in GCC?.
Is this code non-standard?.
Is the SFINAE trickery exclusive of C++11?
Why I'm getting the invalid parameter type 'void' error in the struct
sMemberMethodChecker?.
Why the code is valid in MSVC but it isn't in GCC?.
I believe that MSVC is being helpful however GCC is being stringent in this particular code. As it's somehow not allowing Return (Type::*)(void). However one need to dig it more to know the exact reason.
Is this code no-standard?.
Can't say until it doesn't compile. And searching standard for the features like SFINAE is not everyone's cup of tea.
Is the SFINAE trickery exclusive of C++11?
Not at all. SFINAE existed before C++11.
Here is the simplified way of what you want to do:
template<typename ClassName, typename ClassMethodType>
struct HasMethod
{
template<typename Type, Type Object> struct Contains;
typedef char (&yes)[2];
template<typename Class, typename MethodType>
static yes Check (Contains<MethodType, &Class::size>*);
template<typename Class, typename MethodType>
static char Check (...);
static const bool value = (sizeof(Check<ClassName,ClassMethodType>(0)) == sizeof(char));
};
HasMethod<ClassName, ClassMethodType>::value gives you the answer if a certain type member method exists inside it or not.
As of now HasMethod<> is exclusive to the method naming size with user provided type. But you can create a macro for above code and make the function name configurable.
Here is a working demo with g++.