Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions That Will Only Accept Certain Argument Values (C++)

Let me set the scene..

You can open files in a specific mode like this:

#include <fstream>

int main(){

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

    return 0;
}

that second parameter is an enumerated type-
which is why you will get a compiler error attempting this:

#include <fstream>

int main(){

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

    return 0;
}

In this example, the class doesn't have to account for the second parameter being incorrect, and the programmer never has to worry about passing in a nonsensical value.

Question: Is there a way to write functions that must take a particular type AND a particular value?

Let's say I wanted to re-implement a File Handling class similar to the one above. The difference is I'm making the second parameter a char instead of an enumerated type.
How could I get something like this to work:

#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;
}

Going beyond this, can I get the compiler to test the validity of argument values through functional means? Example:

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;}

I believe i've made it clear what I want to do and why I find it important.
Any solutions out there?

like image 695
Trevor Hickey Avatar asked Feb 21 '23 10:02

Trevor Hickey


1 Answers

If you want compile-time checked values, you could write templates rather than function arguments:

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) { /* ... */ }

Usage:

foo<'a'>("hello world");   // OK
foo<'z'>("dlrow olleh");   // Linker error, `foo<'z'>` not defined.

If you want an actual compiler error rather than just a linker error, you could add a static_assert(false) into the primary template.

like image 115
Kerrek SB Avatar answered Feb 24 '23 00:02

Kerrek SB