www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Emplace using private constructor

reply "develop32" <develop32 gmail.com> writes:
In a project I'm working on there are classes that are available 
publicly but I want to disable their construction outside of 
their modules.

class Display
{
    const string name;

    private this(string name)
    {
       this.name = name;
    }

    static Display[] all()
    {
       // Returns all available displays, the only place where 
Display objects
       // are to be constructed.
    }
}

This is easy when using "new". But I'm using std.conv.emplace 
which does not work with private constructors.

"Don't know how to initialize an object of type Display with 
arguments (string)"

Is there any solution to this problem? I know I can just make the 
constructor public but it just feels wrong, I want to keep public 
API as small as possible and it bugs me that language/library 
limits me here.
Jun 07 2013
parent reply "develop32" <develop32 gmail.com> writes:
Nevermind, problem was not worth the question. I just copied code 
from Phobos std.conv.emplace and placed it directly in my code, 
it works since it is in the same module as the private 
constructor.
Jun 07 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
tldr; I had the crazy idea of mixing-in a specialization of emplace but 
failed probably because mixin does not respect template constraints.

On 06/07/2013 06:50 AM, develop32 wrote:

 Nevermind, problem was not worth the question. I just copied code from
 Phobos std.conv.emplace and placed it directly in my code, it works
 since it is in the same module as the private constructor.
But it is too heavy-handed. Your problem exposes a real weakness. Other library code will make assumptions like emplace does below and they will fail if the constructor is not accessible. From std.conv.emplace: // Call the ctor if any static if (is(typeof(result.__ctor(args)))) { // T defines a genuine constructor accepting args // Go the classic route: write .init first, then call ctor result.__ctor(args); } I tried making your code better but not copying emplace's implementation: module display; import std.conv; class Display { private: const string name; this(string name) { this.name = name; } public: static Display emplace(Args...)(void[] chunk, auto ref Args args) { return std.conv.emplace!(Display)(chunk, args); } } Here is a test program: import display; void main() { enum roomNeeded = __traits(classInstanceSize, Display); ubyte[roomNeeded] buffer; auto d = Display.emplace(buffer, "hello"); } But I failed with the same error: Error: static assert "Don't know how to initialize an object of type Display with arguments (string)" Then I thought about mixing in the template but that did not work either: class Display { // ... static Display emplace(Args...)(void[] chunk, auto ref Args args) { mixin std.conv.emplace!(Display, string); } } The error message indicated that mixin was picking the wrong specialization, because it had a template constraint for 'struct': T* emplace(T, Args...)(T* chunk, auto ref Args args) if (is(T == struct)) { // ... } If it picked the one that matched is(T == class) then we would have achieved our goal without copy-pasting. Still, if it worked, it also feels hacky because we would be mixing-in a specialization right inside our function and hope that it would somehow work in our environment. For example, the specialization of emplace has a return statement: return result; What if my function should not return? I guess then we would mix-in inside a wrapper function, call that function, and ignore the return value. I have a feeling that bearophile already has a bug report about all of this but I haven't checked yet. :p Not the same, but it look like it is related to this bug: http://d.puremagic.com/issues/show_bug.cgi?id=9235 Ali
Jun 07 2013
parent "develop32" <develop32 gmail.com> writes:
On Friday, 7 June 2013 at 16:14:25 UTC, Ali Çehreli wrote:
 But it is too heavy-handed. Your problem exposes a real 
 weakness. Other...
Well, its not *that* heavy. // Inside Display class. auto display = alloc!Display; display.__ctor(name); Where alloc(T) is a bigger part of the original emplace code and is widely used. But generally, yeah. It would be nice to fix mixins.
Jun 07 2013