10

Withdecltypestd::is_const変数の constness は、外部から検出できます。しかし、オブジェクトが自身の constness を知ることも可能でしょうか? 使用法は次のようにする必要があります。

#include <type_traits>
#include <iostream>
#include <ios>

struct Test
{
    Test() {}

    bool print() const
    {
       // does not work as is explained in https://stackoverflow.com/q/9890218/819272
       return std::is_const<decltype(*this)>::value; // <--- what will work??
    }
};

int main()
{
    Test t;
    const Test s;

    // external constness test
    std::cout << std::boolalpha << std::is_const<decltype(t)>::value << "\n";
    std::cout << std::boolalpha << std::is_const<decltype(s)>::value << "\n";

    // internal constness test
    std::cout << std::boolalpha << t.print() << "\n";
    std::cout << std::boolalpha << s.print() << "\n"; // <--- false??
}

LiveWorkSpaceでの出力

動機: const メンバー関数が const オブジェクトで呼び出されたのか、それとも非 const オブジェクトから来ているのかを検出できるようにしたいと考えています。たとえば、オブジェクトはキャッシュを表し、メンバーはビューを表すことができます。キャッシュが const の場合、おそらく最適化された描画ルーチンを使用できますが、基になるデータが非 const の場合、描画ルーチンはデータが更新されたかどうかを定期的に確認する必要があります。

: 関連する質問では、const オブジェクトのビルドを中断する方法を尋ねていますが、その答えが私の質問に対して明確な NO を意味するかどうかはよくわかりません。そうでない場合は、さらに使用するために boolean で constness をキャプチャしたいと考えています。

編集:@DanielFreyが指摘したように、コンストラクターはconstnessをテストするのに適した場所ではありません。const メンバー関数はどうですか?


更新: 私の最初の不適切な質問を修正し、回答のさまざまな部分を提供してくれた皆さんに感謝します (コンストラクターの不明確な constness、 の rvaluedness this、 の文脈上の意味const、-後知恵で-私が見落としていた明らかな過負荷のトリック、および影に潜む const 参照のエイリアシングの抜け穴)。私にとって、この質問は最高の Stackoverflow でした。@JonathanWakelyの回答を選択することにしました。これは、constness の概念を強化する定義Mutableとクラスを定義して、私が望むものを誰にでもできる方法で達成する方法を示したからです。Immutable

4

7 に答える 7

6

コンストラクター(元の質問)は不可能です

12.1 コンストラクタ [class.ctor]

4コンストラクタはvirtual(10.3) またはstatic(9.4) であってはなりません。constvolatileまたはconst volatileオブジェクトに対してコンストラクターを呼び出すことができます。constコンストラクタは、 、volatile、またはconst volatile(9.3.2)と宣言してはなりません。constセマンティクス (7.1.6.1) は、volatile構築中のオブジェクトには適用されません。それらは、最も派生したオブジェクト (1.8) のコンストラクターが終了したときに有効になります。コンストラクターは、ref 修飾子を使用して宣言してはなりません。

メンバー関数 (現在の質問) の場合、 aconstconstnon-overload の両方を単純に提供し、両方を boolean テンプレート パラメーターとして constness を取る (プライベート) メソッドに転送できます。

于 2013-03-07T19:07:09.327 に答える
5

他の人が述べているように、オブジェクトがconstメンバー関数内から宣言されたかどうかはわかりません。const同じではないコンテキストで呼び出されているかどうかしかわかりません。

動機: const メンバー関数が const オブジェクトで呼び出されたのか、それとも非 const オブジェクトから来ているのかを検出できるようにしたいと考えています。たとえば、オブジェクトはキャッシュを表し、メンバーはビューを表すことができます。キャッシュが const の場合、おそらく最適化された描画ルーチンを使用できますが、基になるデータが非 const の場合、描画ルーチンはデータが更新されたかどうかを定期的に確認する必要があります。

それを確実に伝えることはできません。

struct A
{
  void draw() { fut = std::async(&A::do_draw, this, false); }
  void draw() const { fut = std::async(&A::do_draw, this, true); }
  void update(Data&);
private:
  void do_draw(bool this_is_const) const;
  mutable std::future<void> fut;
};

A a;
const A& ca = a;
ca.draw();           // object will think it's const, but isn't
Data new_data = ...;
a.update(new_data);  // do_draw() should recheck data, but won't

可変型と不変型を別々に定義することで、型システムでモデル化できます。

struct Base
{
  virtual ~Base();
  virtual void draw() const = 0;
protected:
  void do_draw(bool) const;
};

struct MutableCache : Base
{
  virtual void draw() const { fut = std::async(&Base::do_draw, this, false); }
  void update();
};

struct ImmutableCache : Base
{
  virtual void draw() const { fut = std::async(&Base::do_draw, this, true); }
  // no update function defined, data cannot change!
};

キャッシュが作成された場合、変更できないImmutableCacheことがわかっているため、以前の「const」オブジェクトの考えが置き換えられます。Aは変更される可能性があるため、更新されたデータを確認する必要があります。MutableCache

于 2013-03-07T19:50:23.193 に答える
4

何がうまくいくの?

何も機能しません。

コンストラクターを実行しているオブジェクトは決してconstです。コンストラクターがコースを実行したconstでのみ、変数に割り当てることができます。

また、メンバー関数についても判別できません(使用されている可能性があるため、非定数メンバー関数が含まれconst_castています)

Const-nessは、関数本体自体のプロパティとしてではなく、各呼び出しサイトに存在するプロパティです。

動機:constメンバー関数がconstオブジェクトで呼び出されているかどうかを検出できるようにしたい

あなたはそれをすることはできませんが、あなたは近づくことができます...

class C
{
public:
    void func() const
    {
        std::cout << "const!";
        func_impl();
    }
    void func()
    {
        std::cout << "non-const!";
        func_impl();
    }
private:
    void func_impl() const;
};

オブジェクトは、たとえば、キャッシュとメンバーをビューで表すことができます。キャッシュがconstの場合、おそらく最適化された描画ルーチンを使用できますが、基になるデータが非constの場合、描画ルーチンはデータが更新されたかどうかを定期的にチェックする必要があります。

はオブジェクト自体のプロパティではないconstため、これは信頼性の低い使用法になります。constオブジェクトが使用されているのは、現在のコンテキストのプロパティです。

現在のコンテキストにあることを検出してconstも、オブジェクトが常にコンテキストで処理されていることはわかりませんconst

于 2013-03-07T19:03:33.717 に答える
3

のタイプthis(およびその結果としての*this)は、関数のcv修飾子によって純粋に決定され、実際のオブジェクトがcv修飾されているかどうかによって変化することはありません。

§9.3.2 [class.this] p1

非静的(9.3)メンバー関数の本体では、キーワードthisはprvalue式であり、その値は関数が呼び出されるオブジェクトのアドレスです。thisクラスのメンバー関数のタイプXはですX*メンバー関数が宣言されconstthisconst X*ている場合、のタイプvolatileです。メンバー関数が宣言されている場合、のタイプthisはです。volatile X*メンバー関数が宣言されている場合const volatile、のタイプはthisですconst volatile X*

したがって、メンバー関数の内部constで、呼び出されたオブジェクトがであるかどうかを確認することはできませんが、コンパイラーに、性質に応じて異なる関数を呼び出させることができますconst

struct X{
  void f(){ /* non-const object */ }
  void f() const{ /* const object */ }
};

int main(){
  X x1;
  X const x2;
  x1.f(); // calls non-const 'f'
  x2.f(); // calls const 'f'

  // but beware:
  X const& rx = x1;
  rx.f(); // calls const 'f', because the "object" it's invoked on is const
}

ただし、スニペットに記載されている制限に注意してください。

于 2013-03-07T19:28:04.170 に答える
3

コンストラクターで設定されたメンバー値を使用して、そのように可能かどうかはわかりませんが、オブジェクトはメンバー関数を使用してその定数を報告できます。

struct Test
{
  bool is_const() const
  {
    return(true);
  }

  bool is_const()
  {
    return(false);
  }
};
于 2013-03-07T19:14:40.440 に答える
2

const特定の値が として同時に表示され、として表示されない可能性があるため、これは不可能constです。検討

MyType t = ...;
MyType& nonConstRef = t;
const MyType& constRef = t;

この時点で、 aと非 const 参照の t両方があります。const

于 2013-03-07T19:03:17.033 に答える
2

オブジェクト内の一貫性を検出することはできませんが、動機は…

「 const メンバー関数が const オブジェクトで呼び出されているのか、それとも非 const オブジェクトから来ているのかを検出できるようにしたい。」

それは簡単です。非constオーバーロードを提供するだけです。

オーバーロードは、たとえば次のように、一般的な実装に従うことができます。

#include <type_traits>
#include <iostream>
using namespace std;

class Test
{
private:
    template< class CvTest >
    static void print( CvTest& o )
    {
        cout << boolalpha;
        cout << "> object says: Hey, const = " << std::is_const<CvTest>::value << "!" << endl;
    }

public:
    bool print()        { return (print( *this ), false); }
    bool print() const  { return (print( *this ), true); }
};

int main()
{
    Test t;
    const Test s;

    cout << "External constness test:" << endl;
    cout << boolalpha << is_const<decltype(t)>::value << "\n";
    cout << boolalpha << is_const<decltype(s)>::value << "\n";

    cout << endl;

    cout << "Internal constness test:" << endl;
    cout << boolalpha << t.print() << "\n";
    cout << boolalpha << s.print() << "\n";
}

結果:

外部一貫性テスト:
間違い
真実

内部一貫性テスト:
> オブジェクトは言う: やあ、const = false!
間違い
> オブジェクトは言う:ねえ、const = true!
真実
于 2013-03-07T19:38:21.770 に答える