让我设置场景..
您可以按照以下特定模式打开文件:
#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::lksdjflskdjflksff);
return 0;
}
在这个例子中,类不必考虑第二个参数不正确,程序员也不必担心传递一个荒谬的值。
问题: 有没有办法编写必须采用特定类型 AND 特定值的函数?
假设我想重新实现类似于上面的文件处理类。 不同之处在于我将第二个参数设为char而不是枚举类型 我怎么能得到这样的东西:
#include "MyFileHandler.h"
int main(){
MyFileHandler myfile1;
myfile.open ("filename", 'a'); //GOOD: a stands for append
myfile.open ("filename", 't'); //GOOD: t stands for truncate
myfile.open ("filename", 'x'); //COMPILER ERROR: openmode can not be the value 'x'
return 0;
}
除此之外,我可以让编译器通过功能手段测试参数值的有效性吗? 例如:
void IOnlyAcceptPrimeNumbers(const int & primeNumber);
int function(void);
int main(){
IOnlyAcceptPrimeNumbers(3); //GOOD: 3 is prime
IOnlyAcceptPrimeNumbers(7); //GOOD: 7 is prime
IOnlyAcceptPrimeNumbers(10); //COMPILER ERROR: 10 is not prime
IOnlyAcceptPrimeNumbers(10+1); //GOOD: 11 is prime
IOnlyAcceptPrimeNumbers(1+1+1+1); //COMPILER ERROR: 4 is not prime
IOnlyAcceptPrimeNumbers(function()); //GOOD: can this somehow be done?
return 0;
}
void IOnlyAcceptPrimeNumbers(const int & primeNumber){return;}
int function(void){return 7;}
我相信我已经说清楚我想做什么以及为什么我觉得这很重要 那里有解决方案吗?
答案 0 :(得分:6)
如果您想要编译时选中的值,可以编写 templates 而不是函数参数:
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.
如果您想要实际的编译器错误而不仅仅是链接器错误,可以在主模板中添加static_assert(false)
。
答案 1 :(得分:1)
不,如果你指定你的函数将使用char
,那么它将需要任何字符。
编译器用于检查传递的参数的“分辨率”是类型而不是一组可能的值。
换句话说,你需要为此使用枚举,或者将检查移动到运行时,或做一些可怕的事情:
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
的函数的等价物。传递无效参数时什么都不做是一种合理的策略,就像返回错误或抛出异常一样(尽管有些人会对此提出异议)。
如何处理它取决于你,但它需要在运行时处理,因为编译器没有所有信息。
答案 2 :(得分:0)
您只能在运行时检查值的有效性。如果违反前提条件,您可以使用assert来停止程序执行。
答案 3 :(得分:0)
没有。如果要限制接受的参数,则需要使用枚举或接受从特定接口继承的对象(取决于您想要的复杂程度)。枚举是解决此问题的常用方法。
关于IOnlyAcceptPrimeNumbers的示例设计不合理。如果你想要实现类似的东西,那么最好提供一个像bool setNumber(int number)
这样的类方法,如果数字不是素数,它将返回false。如果你想在costructor中做到这一点,真正的替代方法就是抛出一个异常(这不是很好)。
这个概念是你不能简单地依赖用户只传递参数类型允许的值(正确)子集中的元素。
答案 4 :(得分:0)
虽然比您的要求更具限制性(这限制了特定类型可以容纳的值),但您可以尝试以下方式:
// 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构造函数是私有的,因此只有Vowel本身可以从chars构造对象。所有其他用途均通过复制构造或复制分配完成。
(我想我最初是从Scott Meyers那里学到这种技术的;感谢他/怪我。)