9

Assuming two declarations:

const type x;  // case a
type y;        // case b

is it possible to detect case "a" or "b" in type's constructor so that I can execute different operations?

From the standard §12.1/3 we have that:

A constructor can be invoked for a const, volatile or const volatile object. const and volatile semantics (7.1.6.1) are not applied on an object under construction. They come into effect when the constructor for the most derived object (1.8) ends.

therefore this behaves like expected by never being const-qualified at construction (otherwise how could you edit member objects in the body?). So, it seems it's not possible to use type traits on this.

A use case for this would be the following: assuming you are working with an underlying C API that describe specific objects (in a much wider sense), taking hints on their future use along the lines of:

  • STATIC = will not be modified
  • DYNAMIC = can be modified

one could create a wrapper around those C objects and give a STATIC hint on a const construction, and a DYNAMIC hint on a non const construction. Of course const_cast exists and could mess things up, but I'm assuming sane coding here :P.

Am I missing something (considering also C++11 and C++14)?

Charles
  • 50,943
  • 13
  • 104
  • 142
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • Imagine this were possible and I'd define `const T make();`, and then say `T nonconst = make();`. Boom? – Kerrek SB Mar 09 '14 at 15:38
  • @KerrekSB, well, the copy constructor of `nonconst` would detect its non `const`ness and read the hint of the other object (from `make`) and construct a `DYNAMIC`ally hinted object? – Shoe Mar 09 '14 at 15:41
  • Well, if anything, it'd be really weird and unexpected to make a copy of something and then end up with something different... I think you'd have a hard time arguing that such a thing should be possible. – Kerrek SB Mar 09 '14 at 15:45
  • @KerrekSB, why? The only thing that you should think is: is the object I'm considering `const`? No? Then it will be `STATIC`ally hinted. Yes? Then it will be `DYNAMIC`ally hinted. Also this *hints* would be implementation details, not part of the interface, so the user shouldn't worry about them anyway. – Shoe Mar 09 '14 at 15:48
  • There was a related question some weeks (months?) ago. I suggested making `type` noncopyable and nonmovable, and provide a `create` function, so that you can only bind references to the objects. You'd end up with `auto const& x = make_const();` and `auto&& y = make_nonconst();` but you could still `auto const& x = make_nonconst();` which is unfortunate. Another way could be to use the declared `x` in the `make` function, e.g. `const type x = make(x);` and deduce the const-ness of `x` inside `make` (error-prone as well). – dyp Mar 09 '14 at 16:13
  • @dyp Yep, seems like the only possibility to me. – Sebastian Hoffmann Mar 09 '14 at 16:13
  • 1
    see http://stackoverflow.com/q/15279508/819272 – TemplateRex Mar 09 '14 at 20:46
  • @dyp `const type x = make(x);`... is that really valid/well defined?? What exactly does that do? – Nicu Stiurca Mar 10 '14 at 04:30
  • @SchighSchagh My intention was to write something like `template T make(T&) { return T(std::is_const{}); }`, where no access to `x` takes place (no lvalue-to-rvalue conversion etc.). I think just *forming* a reference at this point is still defined behaviour, it would only be used to deduce the type of the variable being initialized. [Live example](http://coliru.stacked-crooked.com/a/0d1df533b9e0a2dd) – dyp Mar 10 '14 at 11:53

1 Answers1

5

I dont really know if its worth the struggle and this solution is for sure not perfect as we have to use a helper class Object<T>, but atleast it works very similiar to your requested behaviour:

#include <iostream>
#include <type_traits>

template<typename T>
using Object = typename std::conditional<std::is_const<T>::value, typename T::const_type, typename T::type>::type;

template<bool IsConst>
struct FooHelper;

struct Foo
{
    typedef FooHelper<false> type;
    typedef const FooHelper<true> const_type;

protected:

    Foo(bool isConst)
    {
        if (isConst)
            std::cout << "const" << std::endl;
        else
            std::cout << "non-const" << std::endl;
    }

};

template<>
struct FooHelper<false> : public Foo
{
    FooHelper() : Foo(false) {}
};

template<>
struct FooHelper<true> : public Foo
{
    FooHelper() : Foo(true) {}
};

int main()
{
    Object<Foo> obj;
    Object<const Foo> cobj;
}
Sebastian Hoffmann
  • 11,127
  • 7
  • 49
  • 77