【问题标题】:Can Boost assert that a method call instantiation would not compile?Boost 可以断言方法调用实例化不会编译吗?
【发布时间】:2017-01-12 17:12:27
【问题描述】:

以下代码运行良好,我对我的健壮类感到满意。

但是,通过在编译时手动注释和注释来断言某些方法调用实例不会编译,至少是非常乏味的。据我了解,只有通过实际编译才能预见到编译会中断。这是一个 catch22 的情况。但是有没有一些漂亮的方法来绕过它而没有太多的代码混淆?

Boost 有什么可以提供的吗?

#include <tchar.h>
#include <type_traits>

template<int SOMEMEANINGFULNUMBER>
class RobustClass {

private:
    RobustClass() {}

public:
    static RobustClass<SOMEMEANINGFULNUMBER> instance;

    template <int I = SOMEMEANINGFULNUMBER>
    typename std::enable_if<(I != 2) && (I == SOMEMEANINGFULNUMBER)>::type
    doSomething() {
        // Do something smart and useful!
    }
};

template<int SOMEMEANINGFULNUMBER>
RobustClass<SOMEMEANINGFULNUMBER> RobustClass<SOMEMEANINGFULNUMBER>::instance;

typedef RobustClass<0> RobustClass0;
typedef RobustClass<2> RobustClass2;

int _tmain(int argc, _TCHAR* argv[])
{
    RobustClass<0> robustClass0 = RobustClass0::instance;
    RobustClass<2> robustClass2 = RobustClass2::instance;

    robustClass0.doSomething(); // Compiles and runs fine

    // robustClass2.doSomething(); // Beautifully breaks compilation.
                                   // But I want to wrap this call so 
                                   // that it does NOT break the compilation.
                                   // May be a catch22 wish, however.

    return 0;
}

【问题讨论】:

  • I != 2 表示RobustClass&lt;2&gt; 没有doSomething()。因此,根据 SFINAE robustClass2 可以创建,只是 doSomething() 没有声明。正如你提到的;一切都按预期工作。如果您不能调用它,为什么还要在代码中保留robustClass2.doSomething(); 的选项?您有什么额外的好处或价值?
  • @Yakk 为什么程序格式不正确?
  • @Mus campester robustClass2.doSomething();不应该在任何已编译代码的运行安装中,这是实际的一点。但是我需要测试一下,用这么糟糕的结构编译代码是不可能的。 RobustClass 可以用 100ds 的值实例化,但 doSomething 只能从 SOMEMEANINGFULNUMBER 不同于 2 的实例化中调用。
  • 我知道问题是问你如何包装robustClass2.doSomething(),这样它就不会破坏编译。您是否希望只是一个警告?但现在从评论中我更加困惑。看来真正的问题是;这是否可以清除任何出现的robustClass2.doSomething();
  • @Muscampester 啊,我误读了部分技术。我认为 OP 这样做是合法的。

标签: c++11 boost instantiation assert template-meta-programming


【解决方案1】:

我相信您希望能够检查 RobustClass&lt;2&gt;::doSomething() 不能从 RobustClass&lt;2&gt; 类型的实例中调用。

目前,您通过强制中断构建然后将其注释掉来检查这一点。这很烦人,因为每次检查都需要手动编辑代码。

我们可以使用 SFINAE 检测 .doSomething() 是否对类型 T 有效,然后反转测试,如下所示:

namespace details {
  template<template<class...>class Z, class, class...Ts>
  struct can_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;

template<class X>
using do_something_r = decltype( std::declval<X>().doSomething() );
template<class X>
using can_do_something = can_apply<do_something_r, X>;

这会检测X 是否是doSomething 的有效类型。

你可以这样使用测试:

static_assert( !can_do_something<RobustClass<2>&>{}, "doSomething should be disabled" );

can_apply 与 C++20 提议的 is_detected 相似但不完全相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多