我刚刚观察到libc ++的一个奇怪问题,当使用SFINAE来检测模板类型是否是默认构造时.
以下是我能够提出的最小例子:
#include <iostream>
#include <type_traits>
template <typename T>
struct Dummy;
template <>
struct Dummy<int>{};
template <typename T, typename = void>
struct has_dummy : std::false_type {};
template <typename T>
struct has_dummy<C, std::enable_if_t<std::is_default_constructible<Dummy<T>>::value>> : std::true_type{};
int main() {
std::cout << std::boolalpha << has_dummy<int>{}() << '\n';
std::cout << std::boolalpha << has_dummy<double>{}() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
它编译并输出预期的行,true
并false
在使用时使用g ++或clang ++编译libstdc++
.但是,当我尝试使用libc ++(即clang++ -stdlib=libc++ -std=c++1z test.cpp
)编译它时,我收到以下错误:
/usr/bin/../include/c++/v1/type_traits:2857:38:错误:隐式实例化未定义模板'Dummy':public integral_constant
/usr/bin/../include/c++/v1/type_traits:3166:14:注意:在这里请求模板类'std :: __ 1 :: is_constructible>'的实例化:public is_constructible <_Tp>
test.cpp:14:43:注意:在这里请求模板类'std :: …
这有什么问题:
#include <type_traits>
struct A;
template<typename T>
struct B
{
template<typename=std::enable_if<std::is_copy_constructible<T>::value>>
void f1() {}
};
template<typename T>
struct C {};
// Type your code here, or load an example.
int main() {
// Following fails
B<A> b;
// Could use this:
// b.f1<C>();
// This complies
C<A> c;
return 0;
}
/* This to be in or not doesn't make a difference
struct A
{};
*/
Run Code Online (Sandbox Code Playgroud)
我在这里尝试过:https : //godbolt.org/z/NkL44s,使用了不同的编译器:
我希望下面的NDR形成不良,但似乎不是:-(
#include <type_traits>
template <typename T, typename Enabler = void>
struct is_complete : std::false_type {};
template <typename T>
struct is_complete<T, std::void_t<decltype(sizeof(T) != 0)>> : std::true_type {};
class X;
static_assert(!is_complete<X>::type{}); // incomplete type
class X {};
static_assert(!is_complete<X>::type{}); // complete, but already instantiated
Run Code Online (Sandbox Code Playgroud)
注意:假设sizeof(T) != 0
对完整性特征有效(因为没有类型可以使用sizeof(T) == 0
,使用其他常量会强制为特征找到更好的名称:-))
如果已经隐式实例化了隐式实例化的特殊化,它是代码的变体吗?,程序已被宣布为格式错误的程序,无需诊断(NDR),因为该方法 is_complete_helper<X>::test<X>
具有2种不同的含义,具体取决于实例化点.
似乎附近的参考文件使程序形成不良,但并不像我所理解的那样:
在假设实例中对这种构造的解释不同于在模板的任何实际实例化中对相应构造的解释.
函数模板,成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元内具有多个实例化点,并且除了上述实例化的点之外,对于任何这样的实例化.在翻译单元内具有实例化点的专门化,翻译单元的末尾也被认为是实例化的点.类模板的专门化在翻译单元中最多只有一个实例化点.任何模板的特化可以在多个翻译单元中具有实例化点.如果两个不同的实例化点根据单定义规则给出模板特化的不同含义,则程序形成错误,不需要诊断.
我错了 ?或者不幸的是这个程序是正确的.