【问题标题】:C++11 is there a way to test method access level statically?C++11有没有办法静态测试方法访问级别?
【发布时间】:2013-02-18 14:10:12
【问题描述】:

C++11 添加了许多新的类模板,允许静态测试类型特征,即在编译时检测问题。我正在为一个类编写一个测试,我需要确保给定的方法是公开的。

“动态”解决方案是创建一个对象并调用该方法,如果它不起作用,编译器会报错。但是可能会发生不同类型的错误,这会使生成的错误消息更加混乱。如果可能,最好使用静态断言测试方法访问级别。

有可能还是我真的必须为此创建一个对象?

(另外,如果我需要该方法是私有/受保护的,我该怎么办)

【问题讨论】:

  • 如果编译器抱怨,这不是“动态”解决方案...
  • @KerrekSB 对不起,我的错。
  • @Collin 我正在寻找不需要调用该方法的解决方案

标签: c++ unit-testing c++11 static-assert


【解决方案1】:

这是为我编译的:

#include <type_traits>

namespace has_foo_imp
{

template <class T>
auto
test(T&& t) -> decltype(t.foo(), std::true_type());

auto
test(...) -> std::false_type;

}  // has_foo_imp

template <class T>
struct has_foo
    : public std::integral_constant<bool,
                        decltype(has_foo_imp::test(std::declval<T>()))::value>
{
};

class A
{
    void foo();
public:
};

class B
{
public:
    void foo();
};

int
main()
{
    static_assert(!has_foo<A>::value, "");
    static_assert( has_foo<B>::value, "");
}

【讨论】:

  • 为什么不直接继承public decltype(has_foo_imp::test(...))
  • 这实际上在 Clang 3.2 上编译,但不是在 GCC 4.7.2 上。我想知道谁是对的,为什么......
  • @AndyProwl Clang 我想。
  • @Yakk:看起来是正确的。这完全取决于您如何解释“直接上下文”,但我想说在这种情况下,错误确实发生在函数类型的直接上下文中。
【解决方案2】:

据我所知,以下是standards compliant

#include <type_traits>

template<typename T,typename=void>
struct NullaryFooCanBeCalled:std::false_type {};

template<typename T>
struct NullaryFooCanBeCalled<
      T,
      typename std::enable_if<
         std::is_same<
               decltype(std::declval<T>().Foo()),
               decltype(std::declval<T>().Foo())
         >::value >::type
      >:
   std::true_type {};



struct PrivateFoo {private:void Foo() {}};
struct PublicFoo {public:void Foo() {}};
struct ProtectedFoo {protected:void Foo() {}};
struct StrangeFoo {
   struct Bar { void operator()() {}; };
   Bar Foo;
};

#include <iostream>

int main() {
   std::cout << "PrivateFoo:" << NullaryFooCanBeCalled<PrivateFoo>::value << "\n";
   std::cout << "PublicFoo:" << NullaryFooCanBeCalled<PublicFoo>::value << "\n";
   std::cout << "ProtectedFoo:" << NullaryFooCanBeCalled<ProtectedFoo>::value << "\n";
   std::cout << "StrangeFoo:" << NullaryFooCanBeCalled<StrangeFoo>::value << "\n";
}

另一方面,编译器对这种语言怪癖的支持很差。

Clang 3.2 编译并工作。 gcc 4.7.2 构建失败。 Intel 13.0.1 编译但返回错误的值(在每种情况下都为真!)

【讨论】:

  • 这看起来很复杂,我不明白它是如何工作的。如果编译器支持很差(我使用 GCC),我可能不应该使用它,但无论如何 - 你能用文字解释它是如何工作的吗?我的意思是,它所依赖的语言原则是什么?
  • SFINAE -- 基本上,我测试t.Foo() 是否格式正确,如果是,则使用::value = true 的模板专业化成立,否则::value = false 成立。问题在于,在某些编译器中,这种不是错误的特定替换失败被视为错误。另一方面,标准语言足够复杂,我可能是错的,也许它应该是一个错误!
  • 那么我想没有简单的方法......如果一些编译器支持它而另一些不支持,最好等到它得到更好的支持(或者 C++ 有更好的方法来检查访问级别,例如允许直接检查方法访问级别的新类模板,例如 std::is_constructible)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
相关资源
最近更新 更多