views:

96

answers:

6

hello

Suppose:

struct P {
    P(int v);
};

int v;
P p = 0; // allow
P q = v; // Fail at compile time

How can achieve that? any template trick?

I am trying to write allocator which has special pointer properties. unfortunately std implementation uses implicit conversion from int to NULL pointer:

{ return __n != 0 ? _M_impl.allocate(__n) : 0; }

my pointer implementation: http://code.google.com/p/asadchev/source/browse/trunk/projects/boost/cuda/mapped_ptr.hpp

my allocator implementation: http://code.google.com/p/asadchev/source/browse/trunk/projects/boost/cuda/allocator.hpp

I want to enforce explicit construction using raw pointer to avoid nasty problems.

+3  A: 

I don't know why you'd want to do it, but something like:

struct P
{
protected:
    P(int v) {}

public:
    template <int N>
    static P create() { return P(N); }

};

int main()
{
    P p = P::create<0>();
}
Oli Charlesworth
And for completion of the answer, `static_assert(N == 0, "Only 0 is valid.");` within `create`.
GMan
@GMan: Oh yes. I've reread the question, and it indeed appears that the only valid thing is a literal `0`!
Oli Charlesworth
+1  A: 

I don't think there's any direct way to distinguish between a literal and a variable like you want. One alternative is to require the constructor to accept a reference to an integer: This would work with a variable, but not with a literal.

Reinderien
+6  A: 

You can do it but you won't like it

struct P {
private:
    struct null_absorb;

public:
    P(null_absorb *v);
};

int v;
P p = 0; // allow
P q = v; // Fail at compile time

This will only allow null pointer constants. In other words, zero compile time values.

Johannes Schaub - litb
Cheek​​​​​​​​y. :) `null_absorb` doesn't even need to be defined, does it? Not that it really matters. In fact, could you just do: `P(struct null_absord* v);`?
GMan
@GMan ah right, good idea. One hole still exists. You can pass a type that has a `template<typename T> operator T() { }`. :) Doing it with an elaborated type specifier `struct null_absorb*` will declare it as a namespace member though, I think :)
Johannes Schaub - litb
ok, i think this might work
aaa
@Johannes: @Pavel Ah, yea. (Of course, getting into over-engineering territory.) Maybe add another constructor, like `protected: struct ambiguous_constructor; public: P(ambiguous_constructor*)` so such a conversion would be ambiguous. And you're right, it would inject in an undesirable location. :P
GMan
@GMan if i do that, then `0` will be ambiguous too :) Hmm thinking about this again, a plain `operator T()` will already be ambiguous because of the copy constructor. But a `operator T*` will still select the pointer. I can't think of a way to work around this. But as you say it's indeed over-engineering :)
Johannes Schaub - litb
@Johannes: Oh, duh. :S Yeah, I don't think there's a way.
GMan
thank you very much, after few changes I got it to work my way
aaa
A: 

C++ 's static assert might do the trick: http://www.skynet.ie/~caolan/Fragments/C++StaticAssert.html

I think it is from newer C++ however.

Also, what about just initializing it to zero at compile time. Maybe making it constant.

You cannot use `static_assert` on something that's not a compile-time constant expression. Which v never is in the body of constructor.
Pavel Minaev
+2  A: 

Do you really want to allow implicit conversions from int? That could open up a host of unintended coding errors. Since it's really a coding error to pass anything other than 0, you could do one of these:

#include <cassert>
struct P
{
    // Option #1, only allow 0 as an argument.
    explicit P(int v)
    {
        assert(v == 0);
        // other stuff goes here.
    }

    // Option #2, provide a no-argument constructor.
    P()
    {
        // behave like P(0)
    }
};
Kristo
I have to because this is how std::vector<> is implemented
aaa
A: 

What about:

struct P {
    P(int v) { assert(v == 0); }
};

Some compilers might even see it already at compile time if you wrongly use this.

Albert
runtime punishment, not good
aaa