How to elegantly restrict a template argument to be a `<Certain_Class<AnyT>>`? - visual-studio

How to restrict a template argument of Wrapper to be a Wrapper<Any,MyArray<AnyT>> elegantly?
Don't break content assist (Visual Studio).
High readability. Not use a hacky approach.
For some reasons, most solution love to hack.
Make it obvious at the very first line by using C++ syntax rule. (not just green comment)
As far as I know, there are many solutions, but every solution doesn't meet the criteria.
Workaround 1 (template specialization, fail 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
This code is modified from https://stackoverflow.com/a/43518221 (#max66).
Context clue / syntax highlighting of IDE will be confused.
In my case, it marks some correct types as error e.g. :-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
Workaround 2 (some hacky field/typedef, fail 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
This idea come from a comment in https://stackoverflow.com/a/43518295 (#Jarod42)
The class declaration doesn't mention about MyArray, it just uses a hacky (less readable) way (MyArrayT) to enforce that T2 is MyArray.
Workaround 3 (base class, fail 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
The code is modified from Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types.
It has same disadvantage as workaround 2.
It is not obvious for common user.
Workaround 4 (SNIFAE, fail 1)
By adding std::enable_if on the template class declaration (Wrapper), I can get a working hack.
Unfortunately, content assist hate it.
Reference
Here are the other links that I read :-
http://www.informit.com/articles/article.aspx?p=376878 (template template parameter)
restrict a template function, to only allow certain types (not related to template type as a parameter)

You can write a custom type trait is_specialization, as follows:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
Then you just need to static_assert that is_specialization is true for the given template argument:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};

Related

Changing code to not use namespaces from boost

namespace boost { namespace serialization {
template<class Archive>
void save(Archive & ar, const my_class & t, unsigned int version)
{
....
}
template<class Archive>
void load(Archive & ar, my_class & t, unsigned int version)
{
....
}
}}
I need to use this code within a class but I'm getting errors due to the namespaces. Any help? From the docs: https://www.boost.org/doc/libs/1_47_0/libs/serialization/doc/serialization.html#splittingfreefunctions
Thanks in advance!
You are confusing intrusive serialization (member function) with unintrusive (free functions).
The coffee you post is for free functions (which can be used eg when you cannot add serialization code to a class (it might be from a third party header).
Inside a class definition you should take the member functions approach: https://www.boost.org/doc/libs/1_72_0/libs/serialization/doc/serialization.html#member
If you also need to split save/load functions you can do that as member functions too: https://www.boost.org/doc/libs/1_72_0/libs/serialization/doc/serialization.html#splittingmemberfunctions
The answer was to just place the entirety of the namespace outside of the class.

Diffetence between enable_if usages

As cppreference indicates:
std::enable_if can be used as an additional function argument (not applicable to operator overloads), as a return type (not applicable to constructors and destructors), or as a class template or function template parameter.
Is that because it doesn't make any difference where exactly enable_if is used in a template class or template function - the only thing that matters is the fact that it IS used in a template class or template function (and will remove an instantiation from an overload resolution set)?
Could it be also used this way for example
template<typename T>
class X {
public:
void someFunc() {
enable_if<is_integral<T>::value, int>::type dummy;
}
};
to achieve the same effect as when being used as cppreference indicates?

Inferencing the typename of 'this' in a virtual method

I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.

Why can a std::vector of uncopiable objects not be initialized with an initializer_list?

Why does this not compile? (it needs a copy-constructor for std::unique_ptr<>)
std::vector<std::unique_ptr<int>> vec{std:unique_ptr<int>(new int)};
The created pointer is an r-value so why can it not be moved into the vector?
Is there an equally short way of initializing the vector that works?
The simple problem is that std::unique_ptr's copy-ctor is deleted, but the construct of std:: that is found invokes ::new which triggers a call to that deleted copy-ctor.
libc++/clang++-3.5
/usr/include/c++/v1/memory:1645:31: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >'
template <class _Up, class... _Args>
_LIBCPP_INLINE_VISIBILITY
void
construct(_Up* __p, _Args&&... __args)
{
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
}
libstdc++/g++-4.9
/usr/include/c++/4.9/bits/stl_construct.h:75:7: error: use of deleted function
‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&)
[with _Tp = int; _Dp = std::default_delete<int>]’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
It somewhat tempting to try and formulate a custom overload of std::allocator as use it for the container's allocator type.
For those who cannot resist that temptation (like me)
To make a custom allocator at least used by the compiler it at least needs this minimum population.
template<typename T>
struct allocator : public std::allocator<T> {
using Base = std::allocator<T>;
using Base::Base;
template<typename U>
struct rebind {typedef allocator<U> other;};
template<typename Up, typename... Args>
void construct(Up* p, Args&&... args);
};
That is hardly complete yet (let alone would I have construct properly re-implemented yet), but at least it summons the error up from the abysses of the lib into the daylight a custom source file.

Possible to use SFINAE to pick between a shared pointer factory which uses make_shared vs shared_ptr constructor?

Background: I'm trying to create perfect-forwarding factory methods for creating shared pointers of classes, where it's very clear when someone is calling one that might have a side-effect by taking in a non-const lvalue as a constructor parameter. See: SFINAE enable_if for variadic perfect forwarding template on reference/pointer const-ness So far so good.
However, now my problem is that when using make_shared to create classes that have private or protected constructors, even if they friend my 'builder' class template instance for themselves, the inner make_shared doesn't have access to the constructor.
I had hoped I could SFINAE on that too, by making a wrapper class which itself tries to use make_shared to create a member variable in the same fashion as my builder plans to, and then use that in an enable_if<is_constructible<...>> but that returns true (in gcc 4.8.2) even if trying to actually instantiate such a class doesn't compile:
template<typename R>
struct builder {
class MakeSharedConstructTest
{
public:
template<typename... Args>
MakeSharedConstructTest(Args&&... args)
: m_R(std::make_shared<R>(std::forward<Args>(args)...))
{}
private:
std::shared_ptr<R> m_R;
};
};
struct NonPublic
{
friend class builder<NonPublic>;
private:
NonPublic() {};
};
. . .
// prints 1, ie yes, constructible
std::cout << std::is_constructible<builder<NonPublic>::MakeSharedConstConstructTest>::value << "\n";
// test.cpp:134:3: error: ‘NonPublic::NonPublic()’ is private
builder<NonPublic>::MakeSharedConstConstructTest q;
What am I missing here?

Resources