SFINAE 在 Visual Studio 2012 上使用 decltype() 忽略 "private"
SFINAE using decltype() ignores "private" on Visual Studio 2012
我正在尝试创建一个元函数,它将告诉我类型 T 是否可以在布尔上下文中使用,即是否像这样的代码
decltype(T) x = /* ... */;
if (x) { /* ... */ }
将编译。
我使用了一些 C++11 功能,但仅限于 VS 2012 中可用的功能,因为我希望我的代码也能在那里工作。
这是我的代码:
#include <type_traits> // want to use remove_reference and declval from std library
// objects of this type can be used in a boolean context
class AlmostBoolean
{
public:
operator bool() const { return true; }
};
// should not be used in a boolean context because it requires two user-defined conversions
class RequiresTwoConversions
{
public:
operator AlmostBoolean() const { return AlmostBoolean(); }
};
// should not be used in a boolean context because the conversion operator is private
class PrivateBoolean
{
private:
operator bool() const { return true; }
};
namespace kinda_sorta_type_traits
{
typedef char(&yes_type)[1];
typedef char(&no_type) [2];
using std::remove_reference;
using std::declval;
template<typename T>
struct can_be_used_in_a_boolean_context
{
template<typename U>
static yes_type test(typename remove_reference
<
decltype( static_cast<bool>(declval<const U &>()) )
>::type *);
template<typename>
static no_type test(...);
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes_type);
};
}
using kinda_sorta_type_traits::can_be_used_in_a_boolean_context;
static_assert( can_be_used_in_a_boolean_context< bool >::value, "");
static_assert( can_be_used_in_a_boolean_context< bool & >::value, "");
static_assert( can_be_used_in_a_boolean_context< int >::value, "");
static_assert( can_be_used_in_a_boolean_context< const volatile int & >::value, "");
static_assert( can_be_used_in_a_boolean_context< AlmostBoolean >::value, "");
static_assert( can_be_used_in_a_boolean_context< AlmostBoolean & >::value, "");
static_assert( ! can_be_used_in_a_boolean_context< RequiresTwoConversions >::value, "");
static_assert( ! can_be_used_in_a_boolean_context< RequiresTwoConversions & >::value, "");
//#ifndef _MSC_VER
static_assert( ! can_be_used_in_a_boolean_context< PrivateBoolean >::value, "");
//#endif
int main()
{
}
这种方法有两个 static test() 函数的重载——一个指向从 decltype(expression) 推导出的东西的指针(顶级引用被剥离,这样我总是可以声明一个指向该类型的指针),另一个采用“...”——通常对我写的其他类似类型特征非常有效。
但是对于这个,我有一个问题。 Visual Studio 2012 抱怨最后一个 static_assert,声称 PrivateBoolean 类型的元函数值应该为真,尽管有这样的代码
int main()
{
PrivateBoolean x;
if (x) {
}
}
无法编译,原因很明显:
error: C2248: 'PrivateBoolean::operator bool' : cannot access private member declared in class 'PrivateBoolean'
我还在 GCC 4.9.1 上测试了这段代码,它在那里工作得很好。
这是 MSVC 编译器中的错误,还是我的推理有误?
更新:
在 Visual Studio 2015 年检查了完全相同的代码。该错误(我相信它实际上是一个错误)已修复。没有错误。只有 IntelliSense 仍然抱怨这个 static_assert 应该会失败,但与原来的问题相比这没什么大不了的:)
但仍然存在一个问题:Visual Studio 2012 可以采取什么变通方法来使这种类型特征在那里正常工作?
听起来很有道理,这是一个 Visual Studio 2012 年的错误。
我正在尝试创建一个元函数,它将告诉我类型 T 是否可以在布尔上下文中使用,即是否像这样的代码
decltype(T) x = /* ... */;
if (x) { /* ... */ }
将编译。
我使用了一些 C++11 功能,但仅限于 VS 2012 中可用的功能,因为我希望我的代码也能在那里工作。
这是我的代码:
#include <type_traits> // want to use remove_reference and declval from std library
// objects of this type can be used in a boolean context
class AlmostBoolean
{
public:
operator bool() const { return true; }
};
// should not be used in a boolean context because it requires two user-defined conversions
class RequiresTwoConversions
{
public:
operator AlmostBoolean() const { return AlmostBoolean(); }
};
// should not be used in a boolean context because the conversion operator is private
class PrivateBoolean
{
private:
operator bool() const { return true; }
};
namespace kinda_sorta_type_traits
{
typedef char(&yes_type)[1];
typedef char(&no_type) [2];
using std::remove_reference;
using std::declval;
template<typename T>
struct can_be_used_in_a_boolean_context
{
template<typename U>
static yes_type test(typename remove_reference
<
decltype( static_cast<bool>(declval<const U &>()) )
>::type *);
template<typename>
static no_type test(...);
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes_type);
};
}
using kinda_sorta_type_traits::can_be_used_in_a_boolean_context;
static_assert( can_be_used_in_a_boolean_context< bool >::value, "");
static_assert( can_be_used_in_a_boolean_context< bool & >::value, "");
static_assert( can_be_used_in_a_boolean_context< int >::value, "");
static_assert( can_be_used_in_a_boolean_context< const volatile int & >::value, "");
static_assert( can_be_used_in_a_boolean_context< AlmostBoolean >::value, "");
static_assert( can_be_used_in_a_boolean_context< AlmostBoolean & >::value, "");
static_assert( ! can_be_used_in_a_boolean_context< RequiresTwoConversions >::value, "");
static_assert( ! can_be_used_in_a_boolean_context< RequiresTwoConversions & >::value, "");
//#ifndef _MSC_VER
static_assert( ! can_be_used_in_a_boolean_context< PrivateBoolean >::value, "");
//#endif
int main()
{
}
这种方法有两个 static test() 函数的重载——一个指向从 decltype(expression) 推导出的东西的指针(顶级引用被剥离,这样我总是可以声明一个指向该类型的指针),另一个采用“...”——通常对我写的其他类似类型特征非常有效。
但是对于这个,我有一个问题。 Visual Studio 2012 抱怨最后一个 static_assert,声称 PrivateBoolean 类型的元函数值应该为真,尽管有这样的代码
int main()
{
PrivateBoolean x;
if (x) {
}
}
无法编译,原因很明显:
error: C2248: 'PrivateBoolean::operator bool' : cannot access private member declared in class 'PrivateBoolean'
我还在 GCC 4.9.1 上测试了这段代码,它在那里工作得很好。
这是 MSVC 编译器中的错误,还是我的推理有误?
更新:
在 Visual Studio 2015 年检查了完全相同的代码。该错误(我相信它实际上是一个错误)已修复。没有错误。只有 IntelliSense 仍然抱怨这个 static_assert 应该会失败,但与原来的问题相比这没什么大不了的:)
但仍然存在一个问题:Visual Studio 2012 可以采取什么变通方法来使这种类型特征在那里正常工作?
听起来很有道理,这是一个 Visual Studio 2012 年的错误。