To answer the question: Is it portable?
No it's not even possible
Details:
It is impossible without erasing styles (for which RTTI / dynamic_cast is not required, but at least a virtual function is required). Working solutions for deleting styles already exist ( Boost.Any )
The reason is as follows:
Creating an instance of the template class means that the compiler displays the size of the member variables so that it can allocate the object on the stack.
However, in your implementation:
private: union { error_type mError; T mValue; };
You have an error_type variable that you want to use in a polymorphic way. However, if you correct the type when creating an instance of the template, you will not be able to change it later (another type may have a different size! You could also impose the size of objects on yourself, but do not do this. Ugly and hacky).
So, you have 2 solutions, use virtual functions or use error codes.
You may be able to do what you want, but you cannot do this:
Result<int> r; r.setError(...);
with the exact interface you want.
There are many possible solutions, if you enable virtual functions and error codes, why don’t you need virtual functions here? If performance is important, remember that the cost of "setting" the error is equal to setting the pointer to the virtual class (if you have no errors, you do not need to enable Vtable, and in any case, Vtable in the template will most likely be optimized in most cases).
Also, if you do not want to "highlight" error codes, you can pre-select them.
You can do the following:
template< typename Rtype> class Result{
If you have 1 type of result or 1 pointer to a virtual class with the required error. You check the boolean to see if you currently have an error or result, and then you get the corresponding value from the union. The virtual cost is paid only if you have a mistake, and for a regular result you only have a penalty for a Boolean check.
Of course, in the above solution, I used a pointer to the result, because it allows you to get a general result, if you are interested in the results of a basic data type or POD structure with only basic data types, then you can avoid using a pointer for the result.
Note in your case, std::exception_ptr already gaining erasure , but you lose type information to get information about the missing type again, you can implement something like std::exception_ptr , but with enough virtual methods to ensure safe casting for the correct type of exception.