Можно использовать SFINAE вместе с новыми метафункциями из <type_traits>
для проверки условий типов в обратной строке функции. Если условия не выполняются для некоторых шаблонов функций и не выполняются для других, SFINAE следит за тем, чтобы компилятор шел дальше, и выбирал наилучшего кандидата для шаблона функции.
Это работает, конечно, если условия ваших типов можно проверить во время компиляции. В этом небольшом примере проверяется, могут ли два типа присваиваться друг другу, а затем включается тип возврата. Если типы нельзя назначить (комбинации C с (A, B)), компиляция завершится неудачно:
#include <type_traits>
#include <cassert>
class A;
class B;
class C;
class A
{
public:
void operator=(B const& b) {};
};
class B
{
public:
void operator=(A const& a) {};
};
class C {};
template<class RetT, class InT>
std::enable_if_t
<
std::is_assignable<InT,RetT>::value,
RetT
>
getData(InT*)
{
RetT result;
return result;
};
using namespace std;
int main()
{
A* Aptr = new A;
B* Bptr = new B;
C* Cptr = new C;
getData<A>(Bptr);
getData<B>(Aptr);
// Assignments not there, so the compilation fails.
getData<B>(Cptr);
getData<C>(Bptr);
getData<A>(Cptr);
getData<C>(Aptr);
delete Aptr;
Aptr = nullptr;
delete Bptr;
Bptr = nullptr;
delete Cptr;
Cptr = nullptr;
return 0;
};
Вы также можете использовать if constexpr
в теле функции, если вы можете использовать C ++ 17:
template<class RetT, class InT>
RetT
getData(InT*)
{
if constexpr (std::is_assignable<InT,RetT>::value)
{
RetT result;
return result;
}
else assert(false && "RetT and IntT not assignable.");
};
if constexpr
оценивается во время компиляции и если true
RetT result;
return result;
компилируется, в противном случае оператор assert компилируется. Если вы попытаетесь использовать функцию с комбинациями C, (A, B), вы получите ошибку времени выполнения:
RetT getData(InT*) [with RetT = B; InT = C]: Assertion `false && "RetT and IntT not assignable."' failed.
Если вы хотите, чтобы подтверждение активировалось во время компиляции, вы можете использовать static_assert
.