Я хочу написать функцию, которая возвращает экземпляр типа T, но ведет себя по-разному в зависимости от того, как можно построить T. Скажем, у меня есть такие структуры
#include <type_traits>
#include <iostream>
struct A {};
struct B {};
struct C {
C(A a) {
std::cout << "C" << std::endl;
}
};
Я хочу создать C, задав им A. У меня есть такая структура, которая использует enable_if для выбора одной из двух функций:
struct E {
template< bool condition = std::is_constructible<C, A>::value,std::enable_if_t<condition,int> = 0>
C get() {
return C{A{}};
}
template< bool condition = std::is_constructible<C, B>::value,std::enable_if_t<condition,bool> = false>
C get() {
return C{B{}};
}
};
Это прекрасно компилируется с g ++ 82 (и я думаю также с g ++ 9), но clang9 выдает мне ошибку
$ clang++ --std=c++17 main.cpp
main.cpp:26:12: error: no matching constructor for initialization of 'C'
return C{B{}};
^~~~~~
main.cpp:6:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B' to 'const C' for 1st argument
struct C {
^
main.cpp:6:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'B' to 'C' for 1st argument
struct C {
^
main.cpp:7:3: note: candidate constructor not viable: no known conversion from 'B' to 'A' for 1st argument
C(A a) {
^
1 error generated.
, хотя enable_if должен скрывать эту функцию. (Звоню E e; auto c = e.get();
). Если я не жестко кодирую C, а вместо этого использую шаблон для передачи C, он работает в обоих компиляторах.
template<typename T>
struct F {
template< bool condition = std::is_constructible<T, A>::value,std::enable_if_t<condition,int> = 0>
T get() {
return T{A{}};
}
template< bool condition = std::is_constructible<T, B>::value,std::enable_if_t<condition,bool> = false>
T get() {
return T{B{}};
}
};
Я не понимаю, почему clang явно проверяет тело функции даже хотя функция должна быть отключена enable_if.