5

我想写一个模板函数,只能用于2个数字(例如3和5),并给出错误,如果你尝试使用它与另一个数字。关于ints的专业化,和static_assert

我可以这样做:

template<int x> 
void f(); 

template<> 
void f<3>() 
{ 
    cout << "f<3>()\n"; 
} 


template<> 
void f<5>() 
{ 
    cout << "f<5>()\n"; 
} 

,然后我可以调用这个函数的正常方式:

f<3>(); 
f<5>(); 

并将其编译好了,如果我尝试使用我的功能不正确:

f<10>(); 

编译器给我一个错误。

我有这个方法的2个问题:

1.-是这个标准吗?我可以用ints专门设计一个模板吗?

2.-如果你使用这种方法,我不喜欢你得到的错误,因为错误不会告诉用户他错误地做了什么。我更喜欢写这样的东西:

template<int x> 
void f() 
{ 
    static_assert(false, "You are trying to use f with the wrong numbers"); 
} 

但这不能编译。看来我的编译器(gcc 5.4.0)试图首先实例化主模板,并且因为它提供了错误(static_assert)。

谢谢你的帮助。

如果你想知道为什么我想这样做,是因为我正在学习如何编程一个微控制器。在微控制器中,你有一些只能做一些事情的引脚。例如,引脚3和5是可以产生方波的引脚。如果一个应用程序,我想产生方波,我想写的财产以后,如:

square_wave<3>(frecuency); 

但是,如果几个月后,我想重用这个代码(或修改)在另一个应用程序与differente微控制器,我想我的编译器对我说:“呃,在这个微控制器中,你不能在引脚3和5上产生方波,而是使用引脚7和9”。我认为这可以为我节省很多麻烦(或者不是,我真的不知道,我只是在学习如何编程一个微控制器)。

+0

“_but这并不compile_” 什么是编译错误?用哪个测试? ''f <10>()''不应该使用静态断言进行编译。 – nefas

+0

@nefas它不能用_any_值的'x'进行编译。 –

回答

2

static_assert的条件始终为false,这使得在选择规范之前无法在重载分辨率中选择主模板。您可以根据tempalate参数x更改static_assert的条件。 .eg

template<int x> 
void f() 
{ 
    static_assert(x == 3 || x == 5, "You are trying to use f with the wrong numbers"); 
} 

LIVE

从标准,$17.7/8,9 Name resolution [temp.res]

紧随其定义模板的假设实例将由于不良形成不依赖于结构模板参数

...

否则,对于可以生成有效专业化的模板,不得发布诊断。

$17.7.2/1 Dependent names [temp.dep]

里面一个模板,一些结构有可能不同从一个实例到另一个语义。这样的结构取决于模板参数。

+0

好吧,但它很hacky。为什么不''删除''功能呢? – Rakete1111

+0

@ Rakete1111因为OP想要一些更明确的定制信息。 – songyuanyao

+1

我想他们只是想要一个编译器错误,而不是一个链接器。但是没问题 :) – Rakete1111

5

1.-是否是标准?我可以用ints专门设计一个模板吗?

是的。

2.

template<int x> 
void f() 
{ 
    static_assert(false, "You are trying to use f with the wrong numbers"); 
} 

你需要改变静态断言条件到的东西,是依赖于模板参数的值。一些简单的事情

template <int x> 
void f() 
{ 
    static_assert(x - x, "You are trying to use f with the wrong numbers"); 
} 

应该工作。


顺便说一句,这是值得注意的是,它通常被认为不是一个好主意,专门函数模板,为一体的专业化交互严重(或至少有点不可预知)与函数重载。因此,它可能是一个更好的主意,一般用一个函数对象来代替:

template <int I> 
struct do_f { 
    static_assert(I - I, "You are trying to use f with the wrong numbers"); 
}; 

template <> 
struct do_f<3> { 
    void operator()(args...) { ... } 
}; 

template <> 
struct do_f<5> { 
    void operator()(args...) { ... } 
}; 

然后你就可以编写调用该函数对象的包装功能:

template <int I> 
void f(args...) { 
    do_f<I>{}(args...); 
} 
0

其他的答案只有建议解决方法。尤其是因为它涉及编写一些样板代码。最容易做的事情是

template<int x> 
void f() = delete; 

然后你会得到像

error: call to deleted function 'f' 

一个很好的编译器错误当您尝试实例化一个非专业int模板。

#include <iostream> 

template<int x> 
void f() = delete; 

template<> 
void f<3>() 
{ 
    std::cout << "f<3>()\n"; 
} 

template<> 
void f<5>() 
{ 
    std::cout << "f<5>()\n"; 
} 

int main() 
{ 
    f<3>(); 
    f<5>(); 
    f<10>(); // BOOM! 
} 

Live example