Проверка SFINAE для оператора + =
Я пытаюсь исключить перегрузку из набора перегрузки, если operator+=
отсутствует.
Я знаю, как проверить, является ли T+T
законным:
template<typename T,
typename CheckTplusT = decltype(std::declval<T>() + std::declval<T>())>
void foo(T a, T b, ...)
{
a = a + b;
}
но это не работает для +=
template<typename T,
typename CheckTplusT = decltype(std::declval<T>() += std::declval<T>())>
void foo(T a, T b, ...)
{
a += b;
}
Является ли это фиксируемым, используя другое выражение внутри decltype
или мне нужна другая конструкция SFINAE?
Причина, по которой мне нужно это исключить из набора перегрузки, заключается в том, что он сталкивается с другой перегрузкой, которая принимает функтор, который будет использоваться в качестве альтернативы +=
. Компиляторы - VS2013, gcc4.8
Ответы
Ответ 1
Я бы записал вторую форму как:
template<typename T>
auto foo(T a, T b, ...) -> decltype( a+=b, void() )
{
a += b;
}
Выведенный тип для decltype(a+=b, void())
будет просто void
, если выражение a+=b
допустимо, иначе это приведет к SFINAE.
Ну, даже в первой форме я бы использовал подход типа возвращаемого возврата.
Ответ 2
Вам нужно lvalue
в левой части +=
, но ваше решение имеет значение xvalue. Как указано в комментариях dyp, вы можете использовать declval<T&>
для получения значения lvalue. Это прекрасно работает (просто протестировано):
template<typename T,
typename CheckTplusT = decltype(std::declval<T&>() += std::declval<T>())>
void foo(T a, T b, ...)
{
}
Ответ 3
Добавление этой функции main():
int main()
{
int x = 1, y = 2;
foo( x, y );
}
Это ошибка компилятора:
main.cpp: In function int main(): main.cpp:15:15: error: no matching
function for call to foo(int&, int&)
foo( x, y );
^ main.cpp:15:15: note: candidate is:
main.cpp:7:6: note: template<class T, class CheckTplusT> void foo(T, T, ...) void
foo(T a, T b, ...)
^ main.cpp:7:6: note: template argument deduction/substitution failed:
main.cpp:6:60: error:
using xvalue (rvalue reference) as lvalue
typename CheckTplusT = decltype(std::declval<T>() += std::declval<T>())>
Ключевая строка using xvalue (rvalue reference) as lvalue
Это документация для declval
Это обходное решение работает для меня:
template<typename T,
typename CheckTpluseqT = decltype(*std::declval<T*>() += *std::declval<T*>())>
void foo(T &a, T b, ...)
{
a += b;
}
int main()
{
int a = 1, b = 2;
foo( a, b );
std::cout << a << std::endl;
}
выходы 3
Вы также можете использовать declval<T&>
, конечно.
Ответ 4
Как насчет этого? это метод, используемый до std::declval
.
template<typename T,
typename CheckTplusT = decltype(*(T*)nullptr += std::declval<T>())>
void foo(T a, T b, ...)
{
a += b;
std::cout << "foo with +=" << std::endl;
}