title: Prevent use of a class outside of temporary scope?
body: <p>Is there a way to tell if an instance has been constructed in temporary scope or not, or prevent it from being used outside of temporary scope?  I'm guessing there's not, but then again, I'm always surprised by the ability of C++ to exceed its own design limitations.  </p>
  
  <p>It's kind of a weird question, I admit, and I don't know how to "justify" the desire short of just providing the backstory.</p>
  
  <p>The question arises from a shuttle class we use to glue together a scary number of legacy systems, each with their own notion of how data is represented.  For a familiar example, take strings.  We could overload each method in our API with each "style" of string:</p>
  
  <pre><code>void some_method(const char* arg);
  void some_method(const std::string&amp; arg);
  void some_method(const QString&amp; arg);
  void some_method(const XmlDocString&amp; arg);
  void some_method(const wire_string&amp; arg);
  </code></pre>
  
  <p>Or we could do:</p>
  
  <pre><code>void some_method(const StringArg&amp; arg);
  </code></pre>
  
  <p>Where that helper class is (let's ignore string encodings for now and just assume bad old C-style strings for the purposes of this question):</p>
  
  <pre><code>class StringArg {
  public:
    StringArg() : m_data(""), m_len(0) {}
    template&lt;size_t N&gt;
    StringArg(const char (&amp;s)[N]) : m_data(s), m_len(N-1) {}
    StringArg(const char* s) : m_data(s?s:"") { m_len = strlen(m_data); }      
    template&lt;class T&gt;
    StringArg(const T&amp; t) : m_data(data_from(t)), m_len(len_from(t)) {}
    const char* data() const { return m_data; }
    const char* size() const { return m_len; }
  private:
    const char* m_data;
    size_t m_len;
  };
  
  const char* data_from(const std::string&amp; s) { return s.c_str(); }
  size_t len_from(const std::string&amp; s) { return s.size(); }
  
  template&lt;class XmlType&gt;
  const char* data_from(const XmlString&lt;XmlType&gt;&amp; s) { return &amp;s.content()[0]; }
  template&lt;class XmlType&gt;
  size_t len_from(const XmlString&lt;XmlType&gt;&amp; s) { return s.byte_length(); }
  </code></pre>
  
  <p>ADL chooses the various data_from()/len_from() to get us a buffer backed by something else and its size.  In reality there's extra metadata to capture important information about the nature of the buffer and how to iterate it, but the important point for this discussion is that StringArg is used in temporary scope, is cheap to copy, provides fast access to some buffer backed by something else on the outside of the interface whose type we now don't actually need to care about, and that any conversion, argument checking, or length calculations are done once at the boundary.</p>
  
  <p>So there we are, someone is free to call it with two wildly different string classes:</p>
  
  <pre><code>interface_method(header() + body.str() + tail(), document.read().toutf8());
  </code></pre>
  
  <p>We don't need to care about the lifetime or the type of whatever's going on here, and internally we can pass around pointers to those buffers like candy, slice them up, parse them, log them in triplicate, without accidental allocation or lengthy memory copies.  As long as we never <em>hang on</em> to those buffers, internally, this is safe and fast and has been a joy to maintain.</p>
  
  <p>But as this API becomes more widely used, StringArg is (perhaps unsurpisingly) being used in places other than temporary scope, as if it were Yet Another String Class, and the resulting fireworks are impressive.  Consider:</p>
  
  <pre><code>std::string t("hi");
  write(StringArg(t+t)); //Yes.
  StringArg doa(t+t); //NO!
  write(doa); //Kaboom?
  </code></pre>
  
  <p><code>t+t</code> creates a temporary whose content StringArg will point into.  In temporary scope this is routine, nothing interesting to see here.  Outside of it, of course, it's insanely dangerous.  Dangling pointers to random stack memory.  Of course, the second call to write() actually will work <em>just fine</em> most of the time, even though it is most clearly wrong, which makes detecting these mistakes quite difficult.</p>
  
  <p>And here we are.  I want to allow:</p>
  
  <pre><code>void foo(const StringArg&amp; a);
  
  foo(not_string_arg());
  foo(t+t);
  </code></pre>
  
  <p>I want to prevent or detect:</p>
  
  <pre><code>StringArg a(t+t); //No good
  </code></pre>
  
  <p>And I'd be fine if the following wasn't possible, too, even though it's fine:</p>
  
  <pre><code>foo(StringArg(t+t)); //Meh
  </code></pre>
  
  <p>If I could detect the scope this thing was being constructed in, I could actually go and arrange to copy the content into a stable buffer in the constructor, similar to std::string, or throw an exception at runtime, or even better, if I could prevent it at compile time that'd ensure it was only used as designed.</p>
  
  <p>Really, though, I only want StringArg to ever be the type of a method argument.  An end user will never have to type "StringArg" in order to use the API.  Ever.  You'd hope that'd be easy enough to document away, but once some code looks like it works, it multiplies, and multiplies...</p>
  
  <p>I have tried making StringArg non-copyable but that doesn't help much.  I have tried creating an additional shuttle class and a non-const reference to try and fake out the implicit conversions in such a way they go my way.  The explicit keyword seems to make my problem worse, promoting the typing of "StringArg".  I tried messing around with an additional struct with partial specialization which is the only thing that knows how to construct a StringArg, and hiding the constructors for StringArg... something like:</p>
  
  <pre><code>template&lt;typename T&gt; struct MakeStringArg {};
  template&lt;&gt; struct MakeStringArg&lt;std::string&gt; { 
    MakeStringArg(const std::string&amp; s); 
    operator StringArg() const;
  }
  </code></pre>
  
  <p>So then the user has to wrap all arguments with MakeStringArg(t+t) and MakeFooArg(foo) and MakeBarArg(bar)... existing code doesn't compile and in any case it kind of kills joy of using the interface.</p>
  
  <p>I'm not above macro hacks at this point.  My bag of tricks is looking pretty empty about now.  Anyone have any advice?</p>