For example
template <class T1, class T2>
class foo
{
T1 t1;
T2 t2;
T1 bar(); //Always exists
decltype(t1(t2)) baz(); //Should only exist if t1(t2) is valid
};
If baz
is invalid I still want the program to compile as long as nobody actually calls baz
.
You can make
baz
a template, such that if the return type is invalid the member will be SFINAE-d out rather than result in a hard error:The
T
parameter is necessary to make the computed expression type-dependent, or else SFINAE doesn't apply. If you're worried that this implementation detail 'leaks' out and that someone might attemptf.baz<int>()
, you can declarebaz
withtemplate<typename... Dummy, typename T = T1>
and enforce proper usage with e.g.static_assert( sizeof...(Dummy) == 0, "Incorrect usage" );
in the function body. Both approaches do make it harder to take the address of the member: it should look like e.g.&foo<T, U>::baz<>
.Another approach is to introduce a class template specialization:
In this case
&foo<T, U>::baz
is fine for taking the address of the member (assuming it is present of course). Code that is common to both specialization can be factored out in a common base, and if there is a worry that the additional template parameter that is introduced as an implementation detail might leak it is possible to have a 'real'foo
taking only two template parameters in turn inheriting from such an implementation.