From: Dragan Milenkovic on
DeMarcus wrote:
> On 2010-05-19 18:14, Dragan Milenkovic wrote:
>> DeMarcus wrote:
>>> Hi,
>>>
>>> I have a problem. I want to throw ExceptionA derived from Exception,
>>> i.e.
>>>
>>> struct ExceptionA : Exception
>>> {
>>> };
>>>
>>> ExceptionA, ExceptionB, ExceptionC, etc. shall be able to attach text
>>> to the exception directly at construction via function chaining, i.e.
>>>
>>> throw ExceptionA().addText( "Hello" ).addText( "World" );
>>>
>>> The quick way to implement that would be the following.
>>>
>>> struct Exception
>>> {
>>> Exception& addText( const std::string& str )
>>> {
>>> // Add str to some private string.
>>> return *this;
>>> }
>>> };
>>>
>>> Now, the problem comes with the throw.
>>>
>>> throw ExceptionA().addText( "Hello" ).addText( "World" );
>>
>> IMHO, the best argument was the first one you got. Separate
>> responsibilities. This is one of the most important concepts
>> if you desire a clean and understandable design.
>> But, since you don't want to listen to reason, :-D
>> let me make a few attempts...
>>
>> make_exception<ExceptionA>().addText("Hello").addText("World")
>> .addImage(image).throw_me();
>>
>> or do it to an existing exception:
>>
>> chain_wrapper(excA).addText("Hello").addText("World").throw_me();
>>
>> or with variadic templates:
>>
>> chain_and_throw<ExceptionA>(textAdder("Hello"), textAdder("World"));
>>
>> or with a std::initializer_list:
>>
>> chain_and_throw<ExceptionA>({textAdder("Hello"), textAdder("World")});
>>
>> or another flavor:
>>
>> chain_and_throw(excA, {textAdder("Hello"), textAdder("World")});
>>
>> or a variation of the first one:
>>
>> throw make_exception<ExceptionA>().addText("Hello").addText("World")
>> .addImage(image).exception;
>>
>> how about:
>>
>> throw chain_wrapper(excA)(textAdder << "Hello" << "World")
>> (imageAdder << image).exception;
>>
>
> Aha, so you make the last function exception() virtual and implement
> that in each exception like this?
>
> ExceptionA& exception()
> {
> return *this;
> }
>
> Smart!

No no no! That would be against the mentioned principle...
Also, I don't think you can use it like that. Maybe the throw_me()
variant would work, but it is too messy and it would ruin everything
if someone doesn't override that function. That is a bad design.

Here is what I meant...

template <typename Exc>
struct make_exception {
Exc exception;

make_exception & addText(const std::string & text) {
exception.addText(text);
return *this;
}

make_exception & addImage(...) { ...; return *this; }
};

See... Exception has no idea of such thing as "chaining". It is there
to be thrown and to contain useful information. However, this template
is there only to satisfy your desire for a one-liner. In the end, you
throw make_exception<Exc>::exception member.

Hope that helps.

--
Dragan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]