Я рассматриваю вывод шаблона шаблона, доступный с С++ 17. Вот код, который я хотел бы задать:
#include <iostream>
#include <cmath>
using std::endl;
using std::cout;
template<typename T>
struct MyAbs {
template<typename U>
MyAbs(U&& u) : t(std::forward<T>(u))
{ cout << "template" << endl;}
#ifdef ON
MyAbs(const T& t) : t(t) {}
#endif
T operator()() const
{
return std::abs(t);
}
T t;
};
/*
// may need the following
template<typename U>
MyAbs(U&&) -> MyAbs<typename std::remove_reference<U>::type>;
*/
int main()
{
const double d = 3.14;
cout << MyAbs(4.7)() << endl;
cout << MyAbs(d)() << endl;
return 0;
}
Когда MyAbs(const T&)
не -DON
условно (т.е. нет -DON
), оба clang++ и g++ не могут вывести параметр шаблона T
Учитывая -DON=1
, оба компилятора строят простой пример выше.
Во-первых, я также догадался, что вычет должен потерпеть неудачу; компилятор может вывести U
но не T
Ошибки компиляции, которые я получил, были тем, что я ожидал. Пожалуйста, дайте мне знать, если я ошибаюсь.
Если бы я был прав на него, то я не могу понять, почему вывод с U&&
преуспевает, когда добавляется MyAbs(const T&)
. То, что я ожидал, было выведено с ошибкой U&&
, и SFINAE позволяет мне вызывать MyAbs(const T&)
вместо этого для обоих случаев: 4.7 и d. Однако то, что произошло, отличается. Кажется, что эта программа вызывает версию шаблона для версии 4.7 и без шаблона для d
.
$ g++ -Wall -std=c++17 ~/a.cc -DON=1
$ ./a.out
template
4.7
3.14
Кажется, что версия шаблона внезапно стала жизнеспособной. Ожидается ли это? Если да, то какая причина?