Let's say i have a class called Mesh and in Mesh i have different static methods like
static Mesh makeTriangle(...)
with some parameters. Then I also have:
static Mesh makeBox(...): with different type and number of parameters than makeTriangle, and
static Mesh makeSphere(...): with exactly the same type and number of parameters than makeTriangle and so on
How can I create a constructor that takes an const std::string &name as it's first parameter and a variable number of parameters that I can pass to the right "make" method that creates the Mesh object?
Is this possible in c++11?
I tried using variadic templates like this
template<typename... Params>
Mesh(const std::string &name, Params&&... parameters)
: Mesh(init(name, std::forward<Params>(parameters)...)) {}
but at some point in the init method I have to do something like
template<typename... Params>
static Mesh init(const std::string &name, Params&&... parameters) {
if(name == "box") return makeBox(std::forward<Params>(parameters)...)
if(name == "sphere") return makeSphere(std::forward<Params>(parameters)...)
/* and so on */
}
which the compiler would refuse to compile because the parameter pack might not match some make method parameters. I cannot put it in a map that takes a string and outputs a function pointer either since the mentioned make methods have different signatures.
So again how can I do this in c++11?
edit
I think using inheritance to make subclases for each different shape would not be the best choice since all Mesh object are essentially a list of points in space, they are all the same class of object and the only way they differ is in the way they are constructed
Rather than using a string, you should use a tag, such as a tag class:
struct box {};
struct sphere {};
template<class Tag, typename... Params>
static Mesh init(Tag, Params&&... parameters) {
if constexpr (std::is_same<Tag, box>::value) return makeBox(std::forward<Params>(parameters)...)
else if constexpr (std::is_same<Tag, sphere>::value) return makeSphere(std::forward<Params>(parameters)...)
/* and so on */
}
Then your users would call the constructor as e.g. Mesh{box{}, a, b, c}.
As an alternative to a tag class, you could also use an enum and integral_constant:
enum class MeshName { Box, Sphere, ... };
template<class Name, typename... Params>
static Mesh init(std::integral_constant<MeshName, Name>, Params&&... parameters) {
if constexpr (Name == MeshName::Box) return makeBox(std::forward<Params>(parameters)...)
else if constexpr (Name == MeshName::Sphere) return makeSphere(std::forward<Params>(parameters)...)
/* and so on */
}
If your name parameter has to be a string, your only option is to defer parameter checking to runtime and issue a runtime error:
template<typename... Params>
static Mesh init(const std::string &name, Params&&... parameters) {
if(name == "box")
if constexpr (std::is_invocable<decltype(makeBox), Params...>::value)
return makeBox(std::forward<Params>(parameters)...)
else
throw std::invalid_argument("Incorrect arguments for makeBox");
if(name == "sphere")
if constexpr (std::is_invocable<decltype(makeSphere), Params...>::value)
return makeSphere(std::forward<Params>(parameters)...)
else
throw std::invalid_argument("Incorrect arguments for makeSphere");
/* and so on */
}
Methinks you have missed the whole point of inheritance. That point is basically that you keep all the common stuff in Shape (like location) and keep everything shape-specific in sub-classes.
For a start, something like a radius (vital for π-based shapes like circles and spheres) has no place when constructing polygons like triangles and rectangles.
In pseudo-code, what you should be doing is:
class shape:
float x_coord
float y_coord
class rectangle: inherits shape
float width
float height
class circle: inherits shape
float radius
Then you construct the concrete shapes rather than the more abstract ones. These concrete shapes, being sub-classes of shape should be able to use all the common stuff as well as the stuff they add during inheritance.
Related
In summary, I have a class inherited from std::enabled_shared_from_this, and there is a factory method return an std::unique_ptr of it. In another class, I convert the std::unique_ptr of the previous class object to std::shared_ptr, and then I call shared_from_this(), which then throws std::bad_weak_ptr. The code is shown below:
#include <memory>
#include <iostream>
struct Executor;
struct Executor1 {
Executor1(const std::shared_ptr<Executor>& executor,
int x): parent(executor) {
std::cout << x << std::endl;
}
std::shared_ptr<Executor> parent;
};
struct Backend {
virtual ~Backend() {}
virtual void run() = 0;
};
struct Executor: public Backend, public std::enable_shared_from_this<Executor> {
const int data = 10;
virtual void run() override {
Executor1 x(shared_from_this(), data);
}
};
// std::shared_ptr<Backend> createBackend() {
std::unique_ptr<Backend> createBackend() {
return std::make_unique<Executor>();
}
class MainInstance {
private:
std::shared_ptr<Backend> backend;
public:
MainInstance(): backend(createBackend()) {
backend->run();
}
};
int main() {
MainInstance m;
return 0;
}
Indeed changing std::unique_ptr<Backend> createBackend() to std::shared_ptr<Backend> createBackend() can solve the problem, but as I understand, in general, the factory pattern should prefer return a unique_ptr. Considering a good pratice of software engineering, is there a better solution?
[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (23.11.2.5), then [magic happens that makes shared_from_this() work for *p - IT]
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
[util.smartptr.shared.const]/29 Effects: ... equivalent to shared_ptr(r.release(), r.get_deleter())...
template<class Y, class D> shared_ptr(Y* p, D d);
[util.smartptr.shared.const]/10 Effects: ... enable shared_from_this with p
Your example executes std::shared_ptr<Backend>(uptr) where uptr is std::unique_ptr<Backend>, which is equivalent to std::shared_ptr<Backend>(p, d) where p is of type Backend*. This constructor enables shared_from_this with p - but that's a no-op, as Backend doesn't have an unambiguous and accessible base class that is a specialization of enable_shared_from_this
In order for Executor::enable_from_this to work, you need to pass to a shared_ptr constructor a pointer whose static type is Executor* (or some type derived therefrom).
Ok, I find a simple solution, that is, using auto as the return type of the factory function, instead of std::unique_ptr or std::shared_ptr, and keeping std::make_unique inside the factory function. The factory function createBackend should be:
auto createBackend() {
return std::make_unique<Executor>();
}
In this case, the return type can be automatically determined, although I don't know how it works exactly. This code can return either unique_ptr or shared_ptr, which should be better than just using shared_ptr. I tested clang and gcc, and both of them worked, but I am still not sure if this is gauranteed by the type deduction and the implicit conversion.
Update:
Actually, I have found that auto deduces the return type above as std::unique_ptr<Executor> instead of std::unique_ptr<Backend>, which might be the reason why the code works. But using auto has an issue: if you return the smart pointer in an if-else block, where the return type varies depending on some parameters, then auto cannot determine the type. For example:
std::unique_ptr<Backend> createBackend(int k = 0) {
if (k == 0) {
return std::make_unique<Executor>();
}
else {
return std::make_unique<Intepreter>();
}
}
Here, both Executor and Intepreter derive from Backend. I think a correct solution includes:
Inherit Backend instead of its derived classes from std::enable_shared_from_this;
Use dynamic_pointer_cast<Derived class> to cast the shared_ptr to derived class after shared_from_this.
The full code is listed in:
https://gist.github.com/HanatoK/8d91a8ed71271e526d9becac0b20f758
I have a class:
class A
{
public:
A (A& in) {} // How to write a constructor from void* ?
int a;
int b;
const void* data() const { return static_cast<const void *>(this); }
};
I need to pass the class data thru a connection, which takes a void* buffer and "returns" also void*. An instance and some function:
A a;
void send(void* x);
void receive(void* x);
How can I type cast the a to send it as a parameter to foo()? The following code is not valid:
foo(static_cast<A&>(a));
How can I then, create a new object from a void* x pointer? What constructor and type cast to implement?
void* pA;
pA = ...
A a_copy {pA};
What would be the difference, if I have a struct not a class? I assume POD class here.
I would like not to use c-style casts, but rather C++ constructs.
How can I type cast the a to send it as a parameter to foo()? The following code is not valid:
foo(static_cast<A&>(a));
I assume you mean send() instead of foo()? If so, your code is not valid because you are casting it to a reference to A, when send() expects a pointer to void. So:
send(static_cast<void *>(&a));
Or, since you already have a member function that does the casting for you:
send(a.data());
How can I then, create a new object from a void* x pointer? What constructor and type cast to implement?
If you really want to do that, then again your constructor should take a pointer to void as argument, not a reference to another A:
class A
{
public:
A(void* in) {...}
...
};
You could then use std::memcpy() to copy all data into the class
A(void *in) {
std::memcpy(this, in, sizeof *this);
};
Of course, this should only be done if A is a POD type.
What would be the difference, if I have a struct not a class? I assume POD class here.
Nothing. A struct and a class are the same, the exception is just that struct defaults to making members public, and a class defaults to private.
I want to write a class that makes use of numerical quadrature. The quadrature order defines the size of some containers that I will use. I would like to make a type alias for such containers and it has to depend on the quadrature order.
The following code shows my trials. It feels suboptimal in the sense that I have to repeat the order in the type alias definition:
#include <array>
class Quadrature
{
public:
static constexpr unsigned int getOrder()
{
return 3;
}
// This line doesn't compile!
//
// using WeightsContainer = std::array<double, getOrder()>;
//
// g++ says "error: 'static constexpr unsigned int Quadrature::getOrder()'
// called in a constant expression before its definition is complete"
// This line compiles, but repeats the order. :-(
using WeightsContainer = std::array<double, 3>;
private:
WeightsContainer container;
};
One solution that I have found is introducing a template parameter Order. But actually I wanted to determine the quadrature order and introducing the template parameter would make it variable.
Is there a possibility to make the order a compile-time constant and use it within my type alias definition?
Edit:
For completeness, I could of course use a preprocessor define. But that feels old-fashioned. :-)
Edit 2:
Okay, I have found another possibility. I could add a function outside the class scope like this:
constexpr unsigned int order()
{
return 3;
}
But that feels wrong, because this is a property of the class and therefore should be within class scope!
One thing you can do is to move the value into a member variable:
class Quadrature
{
private:
static constexpr unsigned int _order = 3;
public:
static constexpr unsigned int getOrder()
{
return _order;
}
using WeightsContainer = std::array<double, _order>;
// ...
};
If you need more complicated computations instead of just return 3, under C++17 you can use a lambda as #Quentin mentioned:
class Quadrature
{
public:
static constexpr auto getOrder = []()
{
return ...;
};
using WeightsContainer = std::array<double, getOrder()>;
// ...
};
Otherwise, you will need to pull the function outside of class scope for reasons mentioned here.
I am using a std::shared_ptr to point to a Node
template<typename T>
class A
{
class Node
{
T data;
std::shared_ptr<Node> link;
Node(T data, std::shared_ptr<Node> link);
};
void push(T data);
std::shared_ptr<Node> top;
};
template<typename T>
A<T>::Node::Node(T data, std::shared_ptr<typename A<T>::Node> link) :
data(data), link(link)
{
}
template<typename T>
void A<T>::push(T item)
{
if (top == nullptr)
{
top = std::make_shared<typename A<T>::Node>(new typename
A<T>::Node(item, nullptr));
}
else
{
top = std::make_shared<typename A<T>::Node>(new typename A<T>::Node(item, top));
}
}
The resulting declarations and definitions results in the compiler error
Severity Code Description Project File Line Suppression State
Error C2664 'Stack::Node::Node(const Stack::Node &)': cannot convert argument 1 from 'Stack::Node *' to 'const Stack::Node &' memory 901
What do I need to change to conform to <memory>?
A constructor of std::shared_ptr<T> accepts a pointer to T which you have created with new.
The function std::make_shared<T>(args...) does the new for you instead. The arguments you pass to make_shared will be passed on to the constructor of T. So you should almost never pass it a pointer created by new (unless you really want to new a T, and then pass that pointer as an argument to create another T!).
So for example, instead of:
std::make_shared<typename A<T>::Node>(
new typename A<T>::Node(item, top))
do just:
std::make_shared<typename A<T>::Node>(item, top)
(By the way, you don't actually need most of those typename A<T>:: qualifiers. Just plain Node is in scope whenever you're in the scope of A<T> or A<T>::Node, both in the class definitions and member definitions of that class after the member name. A<T>::Node without the typename would also work in those contexts because of the "member of the current instantiation" rule.)
I have a class with a couple of fields, assignment c-tor and move c-tor:
class A{
std::vector<int> numbers;
int k;
public:
A(std::vector<int> &&numbers, const int k):
numbers(numbers), // fast
k(k)
{
// logic
}
A(const std::vector<int> &numbers, const int k):
A(std::move(std::vector<int>(numbers)), k) // copy-and-move vector
{
// empty
}
};
I want to keep logic in one c-tor and call it from others.
Also, I want to support fast move-semantics. And I have to explicitly copy-and-move arguments in the assignment c-tor.
Is there any way to avoid such nested construction and keep all advantages I've listed above?
You could delegate one constructor to the other:
struct A
{
A(const std::vector<int> & v) : A(std::vector<int>(v)) {}
A(std::vector<int> && v)
: v_(std::move(v))
{
// logic
}
// ...
};
The moving constructor is now as fast as it can be, and the copying constructor costs one more move than if you spell both constructors out. If you're willing to pay an extra move, though, you might as well just have a single constructor:
struct A
{
A(std::vector<int> v)
: v_(std::move(v))
{
// logic
}
};
The alternative is to put the common code into a function and call that from both constructors.