C++ 只接受某些参数值(C+;+;)的函数

C++ 只接受某些参数值(C+;+;)的函数,c++,function,templates,c++11,arguments,C++,Function,Templates,C++11,Arguments,让我来安排一下 您可以按以下特定模式打开文件: #include <fstream> int main(){ std::fstream myfile; myfile.open ("filename", std::ios::app); return 0; } 除此之外,我可以让编译器通过函数方法测试参数值的有效性吗? 例如: 我相信我已经清楚地表明了我想做什么以及为什么我觉得这很重要。 有解决方案吗?您只能在运行时检查值的有效性。如果违反了先决条件,您最

让我来安排一下

您可以按以下特定模式打开文件:

#include <fstream>

int main(){

    std::fstream myfile;
    myfile.open ("filename", std::ios::app);

    return 0;
}
除此之外,我可以让编译器通过函数方法测试参数值的有效性吗? 例如:

我相信我已经清楚地表明了我想做什么以及为什么我觉得这很重要。

有解决方案吗?

您只能在运行时检查值的有效性。如果违反了先决条件,您最好使用assert停止程序执行。

否,如果您指定您的函数将使用
字符,它将使用任何字符

编译器用于检查传递参数的“解析”是类型,而不是一组可能的值

换句话说,您需要为此使用枚举,或者将检查移动到运行时,或者执行一些可怕的操作,如:

static void processAorT (char typ, char *fileName) { ... }
void processA (char *fileName) { processAorT ('a', fileName); }
void processT (char *fileName) { processAorT ('t', fileName); |
(顺便说一句,这不是我的建议)


话虽如此,我不确定你的提议是否是个好主意

编译器可能能够检测到无效常量,但如果传入
IOnlyAcceptPrimeNumbers
的参数来自变量,或者更糟的是,来自用户输入,则编译器将不会非常成功

API是调用方和函数之间的契约,如果不遵守该契约的规则,您可以自由地做任何您想做的事情,尽管希望您能够记录它

换言之,该功能应开始:

void IOnlyAcceptPrimeNumbers (int num) {
    if (!isPrime (num)) return;
    // do something with a prime number.
}
(或接受
a
t
但不接受
x
的函数的等效项)。在传递无效参数时不执行任何操作是一种合理的策略,返回错误或抛出异常也是如此(尽管毫无疑问有些人会对此提出异议)


如何处理它取决于您自己,但需要在运行时处理,因为编译器不具备所有信息。

如果需要编译时检查值,可以编写模板而不是函数参数:

template <char> void foo(std::string const &);      // no implementation

template <> void foo<'a'>(std::string const & s) { /* ... */ } 
template <> void foo<'b'>(std::string const & s) { /* ... */ }
模板void foo(std::string const&);//没有实施
模板void foo(std::string const&s){/*…*/}
模板void foo(std::string const&s){/*…*/}
用法:

foo<'a'>("hello world");   // OK
foo<'z'>("dlrow olleh");   // Linker error, `foo<'z'>` not defined.
foo(“你好世界”);//好啊
foo(“dlrow olleh”);//链接器错误,`foo`未定义。

如果您想要一个实际的编译器错误而不仅仅是链接器错误,您可以在主模板中添加一个
static\u assert(false)

否。如果您想要限制接受的参数,您需要使用枚举或接受从特定接口继承的对象(取决于您想要使其复杂程度)。枚举是解决此问题的常用方法

关于IOnlyAcceptPrimeNumbers的示例设计得不好。如果您想要实现类似的功能,最好提供一个类方法,例如
boolsetnumber(int number)
,如果该数字不是素数,它将返回false。如果您想在构造函数中执行此操作,真正的替代方法是抛出一个异常(这样做并不太好)


概念是,您不能简单地依赖于用户只传递参数类型允许的(正确)值子集中的元素。

虽然比您的要求更严格(这限制了特定类型可以容纳的值),但您始终可以尝试以下操作:

// Vowel.h
#ifndef VOWEL_H_
#define VOWEL_H_

class Vowel
{
public:
    static const Vowel A;
    static const Vowel E;
    static const Vowel I;
    static const Vowel O;
    static const Vowel U;

    char get() const { return value; }

private:
    explicit Vowel(char c);

    char value;
};

#endif  /* VOWEL_H_ */


// Vowel.cpp
#include "Vowel.h"

Vowel::Vowel(char c) : value(c) {}

const Vowel Vowel::A('A');
const Vowel Vowel::E('E');
const Vowel Vowel::I('I');
const Vowel Vowel::O('O');
const Vowel Vowel::U('U');
由于char构造函数是私有的,因此只有元音本身可以从char构造对象。所有其他用途均通过复制构造或复制分配完成


(我想我最初是从Scott Meyers那里学到这项技术的;谢谢他/责怪我。)

我会使用一个与assert不同的词,这样就不会将问题与
assert()
混淆,后者通常在发布代码中被忽略。这是一般术语。我同意发布问题,但由于它违反了先决条件,必须声明它不会抛出任何eeption(参见abrahams关于该主题的论文)
open
仍必须检查其参数,因为您可以使用无效模式
myfile.open(“name”,std::ios::openmode(42))。有趣的扩展,但问题是为编译时检查而明确定义的。实际上,在某些情况下,可以使用templates@valdo,模板的缺点与我的“可怕”建议相同,重复代码或必须对链接器隐藏真实(共享)函数。绝对不是我建议的。实际上没有代码重复。您有一个非模板实现函数,它由一个模板函数包装,专门用于允许的参数。@valdo,因此我的注释中的“or:-)在这种情况下与我的答案中的
processAorT
代码等效。在任何情况下,当编译时不知道字符时,它仍然不起作用-这是编译时无法绕过的基本限制。只有一点:在专用函数中,应该调用执行实现的非模板函数。这样,您就有了一个没有代码复制的单一实现,只用于“允许”的值。链接器错误是不祥的,而是考虑在一般版本中使用<代码> StasyAsAsTys<代码>,而不是省略实现。
template <char> void foo(std::string const &);      // no implementation

template <> void foo<'a'>(std::string const & s) { /* ... */ } 
template <> void foo<'b'>(std::string const & s) { /* ... */ }
foo<'a'>("hello world");   // OK
foo<'z'>("dlrow olleh");   // Linker error, `foo<'z'>` not defined.
// Vowel.h
#ifndef VOWEL_H_
#define VOWEL_H_

class Vowel
{
public:
    static const Vowel A;
    static const Vowel E;
    static const Vowel I;
    static const Vowel O;
    static const Vowel U;

    char get() const { return value; }

private:
    explicit Vowel(char c);

    char value;
};

#endif  /* VOWEL_H_ */


// Vowel.cpp
#include "Vowel.h"

Vowel::Vowel(char c) : value(c) {}

const Vowel Vowel::A('A');
const Vowel Vowel::E('E');
const Vowel Vowel::I('I');
const Vowel Vowel::O('O');
const Vowel Vowel::U('U');