Can the following function template be made to actually act based on argument type :
#include <iostream>
#include <memory>
#include <tuple>
#include <typeinfo>
using namespace std;
using UPSTR = unique_ptr<char[]>;
template<typename... Ts>
void uprint(Ts const&... strs){
auto tp = std::tie(strs...);
auto& x = std::get<0>(tp);
if(typeid(x)==typeid(UPSTR)) cout << x.get() << endl;
// Error : no match for 'operator<<' and 'const std::unique_ptr<char []>') :
else cout << x << endl;
}
int main(){
UPSTR str = make_unique<char[]>(10); str.get()[0] = 'A';
uprint(str, "hello");
return 0;
}
?
Error from gcc 12.2 : no match for 'operator<<' and 'const std::unique_ptr<char []>')
https://godbolt.org/z/dYG9r7Koj
(MSVC does compile this !)
>Solution :
The compiler always instantiates the whole body of a function template, no matter whether some if statements can be proven at compile-time to be false. So any syntax/type errors, even in false branches are reported.
But exactly for this use case, there is if constexpr:
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, UPSTR>)
cout << x.get() << endl;
else
cout << x << endl;
typeidis not compile-time construct,decltypeis.std::decay_tremoves references + constness -> easier matching.
Note that since C++20, std::unique_ptr got its operator<< which prints its underlying value exactly through os << x.get() so cout<<x; becomes always valid.