Disabling a constructor using std::enable_if - c++

My aim is to create my own analogue of std::basic_string but with some additional conditions. I want my AnyString<CharType, Traits> to be convertible from std::basic_string<CharType, AnyOtherTraits, AnyAlloc> but I want to disable this constructor for some CharType such that basic_string<CharType> does not exist (compile).
I tried to do something like that:
template<typename OtherTraits, typename Alloc, typename =
std::enable_if_t<!std::is_array_v<char_type> &&
std::is_trivial_v<char_type> &&
std::is_standard_layout_v<char_type>>>
AnyString(const std::basic_string<char_type, OtherTraits, Alloc>&);
And I have ColouredChar, which does not meet the conditions listed inside enable_if_t.
Now, when I'm trying to call the disabled constructor :
std::basic_string<ColouredChar> de("string"_purple);
ColouredString d(de);
I do not only get the compile errors from basic_string but also very strange one, telling me that completely different PRIVATE constructor constructor cannot convert its parameter from basic_string.
Is there any way to make these compile errors more readable? Or at least explain whether there's anything here to worry about.

Basic example for constructor restriction using concepts (not your traits)
#include <type_traits>
#include <string>
// declare your own concept
template<typename type_t>
concept my_concept = std::is_convertible_v<type_t, std::string>; // just a demo concept
class ColouredString
{
public:
// then you can limit your constructor to types satisfying that concept
ColouredString(const my_concept auto& /*arg*/)
{
}
~ColouredString() = default;
};
int main()
{
// ColouredString str{ 1 };
ColouredString str{ "hello world!" };
return 0;
}

just to point out, in addition to exist answer, you don't need to define a concept to use it in require-clause
class ColouredString{
public:
template<typename T>
requires (std::is_convertible_v<T, std::string>)
ColouredString(const T&){}
};
and there is already a std::convertable_to concept
class ColouredString{
public:
ColouredString(const std::convertible_to<std::string> auto&){}
};
fwiw, since you said
I want to disable this constructor for some CharType such that basic_string does not exist
your code fail with string constructor probably simply because you try to create one. it has nothing with ColouredString
std::basic_string<ColouredChar> de("string"_purple); // it already fail here
ColouredString d(de);

Related

How to use Objective-C sources' ExplicitInit class?

In the Objc source code, I found the following code. What is the meaning of this code and how to understand it?
objc/Project Headers/DenseMapExtras.h line:38
template <typename Type>
class ExplicitInit {
alignas(Type) uint8_t _storage[sizeof(Type)];
public:
template <typename... Ts>
void init(Ts &&... Args) {
new (_storage) Type(std::forward<Ts>(Args)...);
}
Type &get() {
return *reinterpret_cast<Type *>(_storage);
}
};
Below is my test code:
class MyC{
public:
long l1;
long l2;
MyC(long _l1, long _l2){
l1 = _l1;
l2 = _l2;
}
};
int main(){
MyExplicitInit<MyC> e1 {};
e1.init();
return 0;
}
The compiler prompts the following error:
In the Objc source code, I found the following code. What is the
meaning of this code and how to understand it?
To me it looks like a kind-of-factory which can be used as an alternative to the Construct On First Use Idiom. An instantiated class here represents a storage for an instance you can initialise and request when needed. As far as I understand it's not supposed to be used for local variables (it doesn't make much sense, despite being technically possible) and this is also suggested by the comments of code section with the said class template:
// We cannot use a C++ static initializer to initialize certain globals because
// libc calls us before our C++ initializers run. We also don't want a global
// pointer to some globals because of the extra indirection.
//
// ExplicitInit / LazyInit wrap doing it the hard way
For the error you are experiencing:
No matching operator new function for non-allocating placement new expression;
include <new>
Assuming that you just added that piece of code somewhere in your own sources, the problem here is that you didn't include the <new> header. As simple as that - the error just says that you need to add #include <new> since so-called placement new is not part of the "default" C++, it's an overloaded operator declared in this header.
Second, your init function expects arguments that matches one of the existing (non-aggregate) constructors of the given class, so you are expected to pass arguments which are either match the constructor parameters or can be implicitly converted to them: e1.init(1l, 2l)
A complete example looks something like this:
#include <_types/_uint8_t.h>
#include <new>
namespace objc {
template <typename Type>
class ExplicitInit {
alignas(Type) uint8_t _storage[sizeof(Type)];
public:
template <typename... Ts>
void init(Ts &&... Args) {
new (_storage) Type(std::forward<Ts>(Args)...);
}
Type &get() {
return *reinterpret_cast<Type *>(_storage);
}
};
};
struct sample_struct {
long l1, l2;
sample_struct(long _l1, long _l2): l1{_l1}, l2{_l2} {}
};
sample_struct& getInstance(bool should_init = false) {
static objc::ExplicitInit<sample_struct> factory;
if (should_init) {
factory.init(1l, 2l);
}
return factory.get();
}

Trait to see if a move constructor exists

How do ask the compiler if a type has a move constructor?
std::is_move_constructible doesn't apply because it will return true even if the type is copy constructible only.
Is there something that will return whether or not there is actually a user-defined move constructor?
EDIT:
For background, I am trying to create a type erased class that will (given a set of types) decide whether or not it is worth saving off a type erased version of the move constructor.
If at least one of these types does have an "interesting" move constructor (non trivial and actually implemented), then it should save off the move constructor, else it won't and will save space
#include <type_traits>
struct NoMove {
NoMove(NoMove const&) {}
//NoMove(NoMove&&) = delete;
};
struct InterestingMove {
InterestingMove(InterestingMove&&) {}
};
template<typename T>
struct is_interesting_move_constructor :
std::integral_constant<bool,
std::is_move_constructible<T>::value &&
!std::is_trivially_move_constructible<T>::value> {};
// Fails:
//static_assert(!is_interesting_move_constructor<NoMove>::value);
// Is fine:
static_assert(is_interesting_move_constructor<InterestingMove>::value);
The problem with this attempt is that it should return false on NoMove but it doesn't because is_move_constructible doesn't return true based on whether or not there is actually a move constructor
Type erased class sketch (think like a std::any but limited to a set of types):
template<typename... Ts> // One of these types will be held
struct type_eraser_thing
{
void* obj; // pointer to actual thing
std::function<void*(void*,void*)> move_constr;
std::function<void*(void*,void const*)> copy_constr;
// Plus other goodies not shown
std::size_t size;
template<typename T>
type_eraser_thing(T const& other)
{
// static_assert to make sure T is in Ts...
// Get the memory
obj = malloc(sizeof(T));
obj = new (obj) T(other);
size = sizeof(T);
// Save the move_constructor
move_constr = [](void* dest, void* src){
return new (dest) T(std::move(*reinterpret_cast<T*>(src)));
};
}
// Other stuff (copy constructor, etc)
//
// The real problem the move constructor:
type_eraser_thing(T&& other)
{
obj = malloc(other.size);
obj = other.move_constr(obj,other.obj);
obj.move_constr = other.move_constr;
other.obj = nullptr;
}
};
In the implementation of the move constructor, it doesn't make sense to have a call to a std::function (not really, but something similar) if the move constructor doesn't do anything, so I want to SFINAE it out if it doesn't do anything
The concept you seem to be looking for is:
template <typename T>
concept C = not std::is_trivially_move_constructible_v<T>;
Here's a demo.
If you don't have c++20, you can write this trait yourself, or just use the right hand side where needed, since it's pretty short.

Is auto(toCast) explicit cast planned in future C++ standard?

I might be completely off-track but ...
while using bunch of explicit conversions from ArrayView to Vector (which I don't want implicit for obvious silent dangerous allocations) such as :
class MyClass
{
void SetInts(ArrayView<int> _view)
{
ints = Vector<int>(_view);
}
Vector<int> ints;
};
I was wondering if such a syntax was planned for future release of C++ (as we already got the auto return which does something quite similar) :
class MyClass
{
void SetInts(ArrayView<int> _view)
{
ints = auto(_view);
}
Vector<int> ints;
};
var = auto(expression) would be a kind of explicit conversion shortcut.
If not, is there some reasons not to write such a thing that I haven't spotted ?
I haven't heard of such proposals.
...But you don't need a new language feature to do that. Something like the following template should work just fine:
#include <utility>
template <typename T>
class auto_cast
{
T &&source;
public:
auto_cast(T &&source) : source(std::forward<T>(source)) {}
auto_cast(const auto_cast &) = delete;
auto_cast &operator=(const auto_cast &) = delete;
template <typename U, typename = decltype(U(std::forward<T>(source)))>
operator U()
{
return U(std::forward<T>(source));
}
};
template <typename T> auto_cast(T &&) -> auto_cast<T>;
Usage: ints = auto_cast(_view);
If not, is there some reasons not to write such a thing that I haven't spotted?
Yes, it's awkward at best and obsfucated at worst.
ints = auto(_view);
it looks like a function call, but using a keyword?
ints = Vector<int>(_view);
here we can see exactly whats happening, construction with possibly eluded copy assignment.

auto x = make_x(...) and this

I have a class template S<T> and because the template parameter is sometimes hard write explicitly I also have a little helper function makeS(...) to deduce the template parameter.
Now the problem is that the constructor of S has a "side effect": it adds itself to a map which then will later be used to iterate over all instances of S. But this effectively makes S<T> s{...}; very different from auto s = makeS(...); (if RVO is not used).
Here is some code which hopefully shows what I'm trying to do. (Note: in the actual program, S has more than a single template parameter and all will be deduced in makeS)
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <utility>
using namespace std;
struct Base
{
virtual ~Base() {}
virtual void f() const = 0;
};
static map<string, Base*> Map;
template <typename T>
struct S : Base
{
T Func;
Base* This;
S(string const& name, T func) : Func(std::move(func)), This(this)
{
//
// Automatically add this struct to Map...
//
Map.insert({name, this});
}
virtual void f() const override { Func(); }
};
template <typename T>
S<T> makeS(std::string const& name, T func)
{
return S<T>(name, std::move(func));
}
void func1()
{
std::cout << "func1\n";
}
int main()
{
struct Func2
{
void operator ()() const {
std::cout << "func2\n";
}
};
//
// This is not possible:
//
// S< ??? > s("s", [](){});
//
// This would be ok:
//
// auto F = [](){};
// S<decltype(F)> s("s", F);
//
auto s1 = makeS("s1", func1);
auto s2 = makeS("s2", Func2());
auto s3 = makeS("s3", [](){ std::cout << "func3\n"; });
//
// Manually adding s1,... to the Map is ok, but that's what
// I want to avoid...
//
// Map.insert({"s1", &s1});
// ...
//
assert(&s1 == s1.This);
assert(&s2 == s2.This);
assert(&s3 == s3.This);
for (auto&& I : Map)
{
I.second->f();
}
}
As I understand it, the map will only contain valid pointers if RVO is used in auto s1 = makeS(...) etc. and this is not guaranteed.
Is there a way to deduce the template parameters while at the same time avoiding the need to manually register s1,...?
Your basic problem is you failed to implement the rule of 3. If your destructor needs non-trivial behavior (and if you register yourself in the constructor, this is the case), you must either implement or block assignment and copy construct (and/or move-assign and move-construct).
In this case, we can implement a move-construct and block move-assign, and copy construct and copy assign are implicitly blocked.
First, add name to S. Then implement a move constructor.
template <typename T>
struct S : Base
{
std::string Name;
T Func;
Base* This; // ?? why ?? this looks both dangerous and useless at the same time!
S( S&& s ): Name(std::move(s.Name)), Func(std::move(s.Func)), This(this) {
s.clear(); // technically `move` need not clear.
map[Name] = this; // overwrite
}
S& operator=(S&& s) = delete; // or implement it
now your object is moveable, and when moved it updates the Map. ~S should, I assume, unregister from Map -- detect if your name is empty (and assert at construction you gain a non-empty name), and if it is don't unregister (as you where already moved from).
Now move-construct and elided-construct have the same semantics. RVO failure results in some inefficiency, but no logical failure. Plus, your type is now moveable, which tends to be really useful.
If you need to maintain object identity, use can use std::unique_ptr:
template <typename T>
std::unique_ptr<S<T>> makeS(std::string const& name, T func)
{
return { new S<T>(name, std::move(func)) };
}
Now moving the pointer from place to place won't move the object; the pointer kept in the map will stay valid.
My suggestions to improve your code:
1) Get rid of the side effect in the constructor. Create objects in a factory method only (makeS in your code; you can make it a static member function of S) and register the S objects in that method. To disable object creation in different ways make constructor(s) private.
2) Disable S objects copying/moving and handle the objects for example as shared_ptr/unique_ptr<S> only. When you disable copying/moving you avoid the problem when your map contains a pointer to invalid objects and now you don't need to rely on RVO.
3) Use std::function<void()> instead of T Func;. In that case your class don't need to be a template class (or it will have less template arguments). That will simplify your code.

How do i use 'auto' in C++ (C++0x)?

What do i have to do to this code to make it compile, it's braking around this line:
auto val = what.getObject();
#include<iostream>
using namespace std;
class CUP{
public:
void whatsHappening(){}
};
class MUG{
public:
void whatsHappening(){}
};
class CupThrower{
public:
CUP cp;
CUP getObject(){ return cp;}
};
class MugThrower{
public:
MUG mg;
MUG getObject(){return mg;}
};
template <typename T> void whatsHappening(T what){
auto val = what.getObject(); //DOES NOT COMPILE
val.whatsHappening();
}
int main(){
CupThrower ct;
MugThrower mt;
whatsHappening(ct);
whatsHappening(mt);
return 0;
}
i am using VS2008 to compile.
Auto isn't supported in VS2008. Use VS2010 and later versions, or another compiler supporting this feature.
Others have said that auto isn't in VC9, which is sort-of true. auto doesn't mean in the current C++ Standard what it means in C++0x. In the current Standard, it effectively means nothing useful. Long story short, you can't use auto the way you're trying to use it here.
But there is an alternative. In this code:
template <typename T> void whatsHappening(T what){
auto val = what.getObject(); //DOES NOT COMPILE
val.whatsHappening();
}
...the problem you're having is val is of an unknown type. If T is CupThrower, then getObject() returns a CUP. Likewise, for MugThrower, getObject() returns a MUG. The way your code is written, you have no way to know the type returned by getObject() based solely on the type of T. So the solution is to add a way to know it. Try this:
class CupThrower{
public:
typedef CUP ObjectType;
ObjectType cp;
ObjectType getObject(){ return cp;}
};
class MugThrower{
public:
typedef MUG ObjectType;
ObjectType mg;
ObjectType getObject(){return mg;}
};
Now the type returned by getObject() is part of the enclosing class. You can change your whatsHappening() function to use this information:
template <typename T> void whatsHappening(T what){
T::ObjectType val = what.getObject(); //DOES COMPILE!
val.whatsHappening();
}
And all is right with the world again.
Auto is a feature only present in C++0x and, therefore, isn't enabled by default in most (if not all) the compilers. Have you used the appropriate options in your compiler to enable it?
It doesn't compile because you're trying to deal with zero-sized non-function objects.
Edit:
Works fine for me in VS2010.