This question already has answers here:
Check if class is a template specialization? [duplicate]
(2 answers)
Generic way to test if a type is a (smart) pointer
(1 answer)
Closed 7 days ago.
By "universal" I mean to success work with const & and custom deleters. May be there are way to check all smart pointers at once?
I want to write some func to check empty variant if it contains only pointers (raw, unique, shared) and check instantiation of it by std::enable_if, but what I should write in condition?
template <typename... T>
std::enable_if_t<???, bool>
IsEmptyVariantOfPointers(const std::variant<T...>& variant) {
bool emptyVariant = true;
std::visit([&emptyVariant](auto&& arg) {
emptyVariant = arg == nullptr;
}, variant);
return emptyVariant;
}
NOTE: I'm interested the option without template function overloading by pointer types.
Maybe there are ways to check all smart pointers at once?
You can write a trait which checks the type of the passed template class to be a certain template class type, as follows:
template<typename Type, template<typename...> class Args>
struct is_specialization_of final : std::false_type {};
template<template<typename...> class PointerType, typename... Args>
struct is_specialization_of<PointerType<Args...>, PointerType> final: std::true_type {};
Now provide a variable template of type bool which checks the template classes (i.e. smart pointers or any customer pinter classes).
template<typename PointerType>
inline constexpr bool is_std_smart_ptr =
is_specialization_of<PointerType, std::unique_ptr>::value
|| is_specialization_of<PointerType, std::shared_ptr>::value;
This can be used in the std::enable_if_t as follows. For simplicity, I have replaced the variadic template arguments with a simple template argument. I leave the variadic version to you.
template <typename T>
std::enable_if_t<is_std_smart_ptr<T>, bool>
IsEmptyVariantOfPointers(const std::variant<T>& variant) {
// .....
}
What are the universal ways to check is_unique_ptr?
If the actual intention is only to find the std::unique_ptr, (one way) you can write dedicated traits for it.
template <typename...> struct is_std_unique_ptr final : std::false_type {};
template<class T, typename... Args>
struct is_std_unique_ptr<std::unique_ptr<T, Args...>> final : std::true_type {};
Related
Here is some code that compiles in GCC (on godbolt at least - can't test locally), for handling a compile-time dependency system - the conversion operator here is to make it easier to take an entity that specifies what it can read/write and reduce it down implicitly to a more restricted form when passing into functions (please pretend that the operator below does some static_assert kind of enforcement).
template<typename... Args>
struct WriteList{};
template<typename... Args>
struct ReadList{};
template<typename Reads = ReadList<>, typename Writes = WriteList<>>
class TypedEntity;
template <typename... ReadTypes, template <typename...> typename Reads, typename... WriteTypes, template <typename...> typename Writes>
class TypedEntity<Reads<ReadTypes...>, Writes<WriteTypes...>>
{
public:
template <typename... OtherReadTypes, typename... OtherWriteTypes>
operator TypedEntity<ReadList<OtherReadTypes...>, WriteList<OtherWriteTypes...>>()
{
return {};
}
};
struct ComponentA{};
struct ComponentB{};
struct ComponentC{};
void TestFunc1(TypedEntity<ReadList<ComponentA, ComponentB>, WriteList<ComponentC>> entity)
{
}
void TestFunc2(TypedEntity<ReadList<ComponentA>, WriteList<>> entity)
{
}
void TestFunc3(TypedEntity<ReadList<ComponentA>, WriteList<ComponentC>> entity)
{
}
int main()
{
TypedEntity<ReadList<ComponentA, ComponentB>, WriteList<ComponentB>> entity;
TestFunc1(entity);
TestFunc2(entity);
TestFunc3(entity);
return 0;
}
But under MSVC (latest, i.e.g 19.28, as well as some other 19.x versions I've sampled (19.14, 19.24, etc)):
error C3547: template parameter 'OtherWriteTypes' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'TypedEntity<Reads<ReadTypes...>,Writes<WriteTypes...>>::operator TypedEntity<ReadList<OtherReadTypes...>,WriteList<OtherWriteTypes...>>'
Is this valid C++ and MSVC is wrong?
Is there a workaround for this issue in MSVC?
Appreciate it.
The error message hints at MSVC's mistake (emphasis mine):
error C3547: template parameter 'OtherWriteTypes' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'TypedEntity<Reads<ReadTypes...>,Writes<WriteTypes...>>::operator TypedEntity<ReadList<OtherReadTypes...>,WriteList<OtherWriteTypes...>>'
It's true it can't be deduced from the function parameters - but for a conversion function, deduction happens from the return type, not the empty parameter list.
So a workaround is to simplify the template signature of the conversion function. Presuming the implementation needs to know the actual ReadTypes... and WriteTypes..., the operator() definition can just call a private ordinary member function which can deduce them from parameters.
template<typename T>
struct is_WriteList_s : public std::false_type {};
template<typename... Args>
struct is_WriteList_s<WriteList<Args...>> : public std::true_type {};
template<typename T>
concept is_WriteList = is_WriteList_s<T>::value;
template<typename T>
struct is_ReadList_s : public std::false_type {};
template<typename... Args>
struct is_ReadList_s<ReadList<Args...>> : public std::true_type {};
template<typename T>
concept is_ReadList = is_ReadList_s<T>::value;
template <typename... ReadTypes, template <typename...> typename Reads,
typename... WriteTypes, template <typename...> typename Writes>
class TypedEntity<Reads<ReadTypes...>, Writes<WriteTypes...>>
{
private:
template <typename... OtherReadTypes, typename... OtherWriteTypes>
TypedEntity<ReadList<OtherReadTypes...>, WriteList<OtherWriteTypes...>>
convert_impl(std::type_identity<TypedEntity<
ReadList<OtherReadTypes...>, WriteList<OtherWriteTypes...>>>) const;
public:
template <is_ReadList OtherReadList, is_WriteList OtherWriteList>
operator TypedEntity<OtherReadList, OtherWriteList>() const
{
return convert_impl(
std::type_identity<TypedEntity<OtherReadList, OtherWriteList>>{});
}
};
I used std::type_identity just as a type-wrapper which doesn't actually have any data members or logic. If not compiling with C++20 support, any dummy template struct would do, or a raw pointer with null argument.
If using a version of MSVC or a /std: switch which does not support concepts, the concepts can be converted to SFINAE tricks or simple static_asserts.
This question already has answers here:
How to detect the presence and type of a member variable given its name?
(2 answers)
Closed 2 years ago.
template <class T>
void packarg(char* &szBuff, T t)
{
if (????)
{
t.pack(szBuff, 10240, &iTmpSize);
}
else
{
memcpy(szBuff, &t, sizeof(T));
}
}
I Have Code like this, if the type T has interface pack then use pack interface, if not, then memcpy it.
So, the question is how I determine whether Type T has Interface "pack" or not.
PS: I'm using C++11.
What you want to do here is write a traits template to determine whether or not a type has that member and that member is callable with a certain set of parameter types.
#include <type_traits>
// a SFINAE helper
template<typename T, typename...>
using first_t = T;
// by default, the trait is false
template<typename...>
struct has_pack_member : std::false_type {};
// if T has a member pack() callable with argument types Args..., the trait is true
template<typename T, typename... Args>
struct has_pack_member<
first_t<
T,
decltype( std::declval<T>().pack( std::declval<Args>()... ) )
>,
Args...
> :
std::true_type
{};
This trait can be used like such in C++17:
if constexpr ( has_pack_member<T, /*argument types*/>::value ) {
t.pack( /*arguments*/ );
} else {
// do something else
}
Before C++17, you need to implement the if and else branches in two separate function templates with the same name, and conditionally enable one or the other based on whether the trait is true or false.
With C++20 and concepts around the corner I wondered if it will be possible to write a concept to check if a Type has a function with a certain name which takes any number of arbitrary arguments.
Take the following code for example (with GCC's current concept TS syntax):
template <typename T>
concept bool Initializable = requires(T t) {
{ t.init() } ->void;
};
struct S {
void init() {}
};
static_assert(Initializable<S>);
The concept Initializable checks if a Type implements a void init() function. Now lets assume there is another Type which also has an init function but one which requires arguments, e.g. an int:
struct T {
void init(int) {}
};
Now in this case the static assertion would fail.
Is there any way to make the Initializable concept ignore the function arguments? This example might seem rather derived, but for something like a generic serializer there might be use-cases for such a concept.
There is a type trait for that, std::is_member_function_pointer. But if you want that the return type is void too, then you can do both at the same time:
template <typename>
struct mptr_returns_void : std::false_type {};
template <typename T, typename ...Args>
struct mptr_returns_void<void(T::*)(Args...)> : std::true_type {};
template <typename T>
concept Initializable = mptr_returns_void<decltype(&T::init)>::value;
I wrote an abstract container template class that should define numeric operators (unary + and -, binary +, - and *) if it make sens for the template parameter (that is, if it is a numeric type).
Then, I would like to apply those numeric operations on containers of containers of numeric values (and on containers of containers of containers of numeric values, and so on).
I wrote the following code. The (A) marker shows how I tried to solve the recursive specialization problem.
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <typename T> /* (A) */
struct is_numeric<GenericContainer<T>> : public std::is_arithmetic<T>{};
/* Classic generic container for non-numeric base types */
template <typename T, bool isNumeric=false>
class BaseContainer : public GenericContainer<T> {};
/* Numeric container: +,-,* operations for numeric base types */
template <typename T>
class BaseContainer<T, true> : public NumericContainer<T> {};
/* Arithmetic base types should map on numeric containers */
template <typename T>
class Container : public BaseContainer<T, is_numeric<T>::value> {};
Then, in a test program, I have the following assertions:
/* Vector inherits from Container */
typedef Vector<int, 3> V3D;
ASSERT(is_numeric<int>::value); /* # => OK */
ASSERT(is_numeric<double>::value); /* # => OK */
ASSERT(is_numeric<V3D>::value); /* # => FAIL */
The two firsts assertions work as expected
Your solution fails for a very specific reason: a template type parameter specialization will match only the exact type, and not any derived type.
If you wish for derived types to also match, you need switch gears and use another strategy. In the age of constexpr switching to functions will let you use overloading resolution to your advantage (as one strategy among others):
// Basis
constexpr bool is_numeric_impl(...) { return false; }
template <typename T>
constexpr bool is_numeric(T const& t) { return is_numeric_impl(&t); }
// Specializations
template <typename T,
typename = std::enable_if<std::is_arithmetic<T>::value>::type>
constexpr bool is_numeric_impl(T const*) { return true; }
template <typename T>
constexpr bool is_numeric_impl(GenericContainer<T> const*) {
return is_numeric((T const*)nullptr);
}
The main benefit being that this solution is open-ended so that other people may reuse the same traits and add specializations; because it uses a white-list.
Boost's enable_if and type traits allow tricks like you need:
template <class T, class Enable = void>
struct is_numeric : public std::is_arithmetic<T> {};
template <class T>
struct is_numeric<T, typename enable_if<is_base_of<GenericContainer<T>, T> >::type>
: public std::is_arithmetic<T> {};
The solution employs SFINAE principle to compile the second version of is_numeric when the template parameter meets the criteria inside enable_if. Notice that the syntax of is_base_of is is_base_of<Base, Derived>. There is more explanation in Boost's enable_if documentation.
Since the relationships in your case are even more complicated, as David Rodriguez kindly mentioned, you should probably make it a bit differently:
template <template <class> class U, class T>
struct is_numeric<U<T>, typename enable_if<is_base_of<GenericContainer<T>, U<T> > >::type>
: public std::is_arithmetic<T> {};
And if you cannot use the libraries themselves, you can always use them as inspiration :)
Did you try :
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <template<class...> class Container, typename T, typename... Rest>
struct is_numeric<Container<T, Rest...>> : public is_numeric<T>{};
Seems to work for me.
You need to define the is_numeric trait for each container, you cannot just use the base definition.
template <typename T, size_t N>
struct is_numeric< Vector<T,N> > : is_numeric< GenericContainer<T> > // *
{};
Also note that the definition of the is_numeric should be similar the one in the comment, not the one in the question. That is, you want to define is_numeric for a container in terms of whether the nested type is numeric or not (so that you can peel off the different layers).
Context
I have a custom comparator that takes another comparator and applies an additional check:
template <template <typename> class Comparator, typename T>
struct SoftOrder : public std::binary_function<T, T, bool> {
bool operator()(const T lhs, const T rhs) const {
return Comparator<T>()(lhs, rhs) && AnotherCheck();
}
};
I have a second class that accepts a comparator, e.g.:
template <template <typename> class Comparator>
class Processor { ... };
It is easy to instantiate a Processor with a standard comparator (e.g. std::less) like so:
Processor<std::less> processor1;
Processor<std::greater> processor2;
However it is not so easy to instantiate with SoftOrder as the compiler correctly complains about the missing second template argument:
Processor<SoftOrder<std::less> > processor3; // <-- Fails to compile
Current Solutions
I have come up with a few solutions prior to posting this question.
First Solution - Lots of Derived Classes
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {};
template <typename T>
struct SoftOrderGreaterThan : public SoftOrder<std::greater, T> {};
The main drawback of this solution is the need to create a new struct every time a new variant is required, e.g.:
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {}; // Never used after the next line.
Processor<SoftOrderLessThan> processor3;
Second Solution - A very specific bind class
template <template <typename> class Comparator>
struct BindToSoftOrder {
template <typename T>
struct type : public SoftOrder<Comparator, T> {};
};
This is slightly better in that we don't need to create the intermediate classes explicitly:
Processor<BindToSoftOrder<std::less>::type> processor3;
The downside is the requirement of a class specialised for this situation which cannot really be generalised by making SoftOrder a template parameter on BindToSoftOrder as this would make it a template<template<template>>> which is not permitted by the standard.
Third Solution - C++11 template aliases
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>;
Nicer than the first option in that it doesn't require the introduction of new classes, however still requires littering the code with this extra code that is only used in passing onwards to another template class:
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>; // Never used again
Processor<SoftOrderLessThan> processor3;
Finally, the question
Is there a generic way to bind my custom comparator to a specific comparator in the following manner?
Processor<SomeCoolMetaTemplateBind<SoftOrder, std::less>::type> processor3;
I believe if all of the template parameters were simple types I could just do something like Processor<boost::mpl::bind<SoftOrder, std::less> >, but the presence of the template type in the template parameter list prevents this from occurring.
An ideal solution would involve C++03, but am happy to hear C++11 solutions as well.
If it's not possible, I hope at least the question was interesting.
Seems like this would work:
template <
template <template <typename> class,class> class U,
template <typename> class X
>
struct SomeCoolMetaTemplateBind {
template <typename T>
struct type : public U<X,T> {
};
};