当且仅当语句不能编译时,我才能编写成功的测试吗?

时间:2010-06-11 04:58:46

标签: c++ templates

我想阻止班上的客户做些蠢事。为此,我使用了类型系统,并使我的类只接受特定类型作为输入。考虑下面的例子(不是真正的代码,为了举例我没有像虚拟析构函数这样的东西):

class MyDataChunk
{
    //Look Ma! Implementation!
};

class Sink;

class Source
{
    virtual void Run() = 0;
    Sink *next_;
    void SetNext(Sink *next)
    {
        next_ = next;
    }
};

class Sink
{
    virtual void GiveMeAChunk(const MyDataChunk& data)
    {
        //Impl
    };
};

class In
{
    virtual void Run
    {
        //Impl
    }
};

class Out
{
};

//Note how filter and sorter have the same declaration. Concrete classes
//will inherit from them. The seperate names are there to ensure only
//that some idiot doesn't go in and put in a filter where someone expects
//a sorter, etc.

class Filter : public Source, public Sink
{
    //Drop objects from the chain-of-command pattern that don't match a particular
    //criterion.
};

class Sorter : public Source, public Sink
{
    //Sorts inputs to outputs. There are different sorters because someone might
    //want to sort by filename, size, date, etc...
};

class MyClass
{
    In i;
    Out o;
    Filter f;
    Sorter s;
public:
    //Functions to set i, o, f, and s
    void Execute()
    {
        i.SetNext(f);
        f.SetNext(s);
        s.SetNext(o);
        i.Run();
    }
};

我不想要的是有人稍后回来然后去,“嘿,看!分拣机和过滤器具有相同的签名。我可以制作一个同时执行这两者的通用!”,从而打破了语义差异{ {1}}需要。

这是一种常见的要求,如果是这样,我该如何为它实施测试?

4 个答案:

答案 0 :(得分:3)

一般来说,没有。如果语句没有编译(即无效ISO C ++),则编译器不再有义务创建可执行文件。

有一个着名的例外,甚至有一个缩写:SFINAE,或替换失败不是错误。粗略地说,在许多情况下(例如重载解析),编译器将隐式地实例化一些模板,以考虑结果。如果编译器尝试无法编译的实例化,然后停止整个编译过程,那将是非常烦人的。因此,在这种情况下,它会默默地丢弃实例化错误。

可以利用此SFINAE机制在编译时确定某些属性。考虑一下:

template<typename T> class Foo() {
  static char test(T);
  static int test(...);
  static const size_t result = sizeof(test(0));
};

现在,如果表达式T(0)编译,即如果0可以转换为T,则Foo :: result是sizeof(char)== 1,否则Foo :: result是sizeof(int)。

答案 1 :(得分:2)

为什么要等到运行时?编译时间检查(例如static asserts)可以让违规代码无法编译。

但是要回答你的问题,我相信不 - 你不能这样做,除非你在测试中运行编译器。

但是,请再次查看编译时断言或concept checks。没有理由等到测试时间才能看到这些错误。

答案 2 :(得分:1)

最新澄清问题很简单:

void foo(Filter*);
void foo(Sorter*);
template<typename T> void test() {
   foo((T*)NULL);
}

如果有人通过了同时使用Filter和Sorter的类,则重载决策是不明确的。

答案 3 :(得分:0)

要测试预期的编译时失败,您需要在自动构建的某种框架中运行测试。框架调用编译器从源代码构建,检查编译返回代码是否符合预期成功/失败,然后运行生成的测试.exe(如果是运行时测试)。

我知道Boost的回归测试中存在这样的特征,尽管我实际上还没有研究过它的实现方式。也许你可以看看那些例子/想法。