这是我的示例代码:
#include <type_traits>
template <bool B>
struct S {
// #1
// template <bool C = B, class = std::enable_if_t<!C>>
// operator S<true>() const { return {}; }
// #2
// operator S<true>() const { return {}; }
};
int main() {
S<true> b1;
S<false> b2;
}
使用 g++ 编译时(https://godbolt.org/z/P46qE8EGG),无论启用选项 #1、选项 #2 还是两者都启用,我都不会收到警告。当我启用 #2 时,我希望收到一个警告,指出它是一个自转换函数,但也许 g++ 没有这样的警告。
真正的问题是用 clang 编译时。仅当我启用 #1 时,我才会收到以下警告:
错误:将“S”转换为自身的转换函数将永远不会被使用[-Werror,-Wclass-conversion]
启用 #2 不会触发此警告,禁用
b1
或 b2
的实例化也不会阻止此警告。到底是怎么回事?这是 clang 的错误吗?
编辑:我特别指的是为什么#1产生警告。其他信息旨在展示我尝试将问题缩小到更小的工作示例
当我启用 #2 时,我希望收到一个警告,表明它是一个自转换函数,但也许 g++ 没有这样的警告。
正确,人们可以期待编译器警告(非标准最佳实践),但不能保证某个编译器会提供它们。
启用 #2 不会触发此警告,禁用 b1 或 b2 的实例化也不会阻止此警告。到底是怎么回事?这是 clang 的错误吗?
Clang 不警告
#2
是正确的,因为它可能会被调用,在删除定义的示例中更容易显示:
template <bool B>
struct S {
// #2
operator S<true>() const = delete;
};
int main() {
S<false> const b1;
S<true> b2 = b1; // error: call to a deleted function
}
为什么?由于隐式复制构造函数复制
S<true> -> S<true>
S<false> -> S<false>
然而
S<false>
到 S<true>
并不是相同意义上的复制操作。
当“copy from”类为
S<false>
时,模板构造函数也存在,因此Clang确实不正确警告该函数永远不会被使用:
#include <type_traits>
template <bool B>
struct S {
// #1
template <bool C = B, class = std::enable_if_t<!C>>
operator S<true>() const = delete;
};
int main() {
S<false> const b1;
S<true> b2 = b1; // error: delete function
}