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
baza template, such that if the return type is invalid the member will be SFINAE-d out rather than result in a hard error:The
Tparameter 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 declarebazwithtemplate<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>::bazis 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'footaking only two template parameters in turn inheriting from such an implementation.