nunojpg
nunojpg

Reputation: 505

c++ function templates with not arbitrary parameters

Consider this c++ code that works fine:

template <size_t N>
int check(std::array<unsigned char, N> buf){
    std::cout << N << "-" << buf.size() << std::endl;
    return 0;
}


int main (int argc, char *argv[])
{
    std::array<unsigned char, 20> a;
    std::array<unsigned char, 30> b;
    std::array<unsigned char, 40> c;

    check(a);
    check(b);
    check(c);

    return 0;
}

Is it possible to explicitly instantiate "check" for N=20 and N=30, but disable any other implicit instantiation?

That means that I would like to get a compile time error if I use "check(c)",

Edit:

In fact I wanted to have the same implementation, so a template was the right choice, and I wanted to just have a compile time error if for some reason I instantiate it with a parameters that is not supposed to exist. Because of that the static_assert (c++11) solution looks the best, as complete for the problem and very human readable.

Upvotes: 0

Views: 97

Answers (5)

user2249683
user2249683

Reputation:

If you are treating the arrays differently, a template is useless in your case. Just provide some overloads:

#include <array>
#include <iostream>

int check(std::array<unsigned char, 20> buf){
    std::cout << "Handling an array of size 20\n";
    return 0;
}

int check(std::array<unsigned char, 30> buf){
    std::cout << "Handling an array of size 30\n";
    return 0;
}
int check(std::array<unsigned char, 40> buf){
    std::cout << "Handling an array of size 40\n";
    return 0;
}


int main (int argc, char *argv[])
{
    std::array<unsigned char, 20> a;
    std::array<unsigned char, 30> b;
    std::array<unsigned char, 40> c;

    check(a);
    check(b);
    check(c);

    // std::array<unsigned char, 0> d;
    //error: no matching function for call to ‘check(std::array<unsigned char, 0ul>&)'
    //check(d);

    return 0;
}

Otherwise, if the code is the same, a static_assert is good choice (see @Joachim Pileborg comment)

Upvotes: 0

Jarod42
Jarod42

Reputation: 217085

An other way is to delete the function:

template <size_t N>
void check(std::array<unsigned char, N> buf) = delete;

void check(std::array<unsigned char, 20> buf)
{
    std::cout << 20 << "-" << buf.size() << std::endl;
}

void check(std::array<unsigned char, 30> buf)
{
    std::cout << 30 << "-" << buf.size() << std::endl;
}

Live example

Upvotes: 0

bolov
bolov

Reputation: 75688

There are a few ways of doing this.

One way would be:

template <size_t N>
typename std::enable_if<N == 20 || N == 30, int>::type
check(std::array<unsigned char, N> buf) {
  //..
}

A few thoughts about choosing between this and static_assert shown in the other answers:

  • static_assert may be viewed by some as more clean, clear way of expressing your constraint than enable_if
  • (the most important difference in my opinion): this way the constraint is part of the function interface, i.e. the definition of the function expresses the constraint. static_assert is part of the implementation. In more complex code this can even affect how the function overloads.
  • with static_assert you get a clear message of what is wrong when the constraint isn’t satisfied.

Upvotes: 2

Austin Brunkhorst
Austin Brunkhorst

Reputation: 21130

You can use static_assert to throw a compile time error if N is anything other than 20 or 30.

template <size_t N>
int check(std::array<unsigned char, N> buf) 
{
    static_assert(N == 20 || N == 30, "N must be 20 or 30.");

    std::cout << N << "-" << buf.size() << std::endl;

    return 0;
}

Upvotes: 4

Baum mit Augen
Baum mit Augen

Reputation: 50053

You can use static_assert:

template <size_t N>
    int check(std::array<unsigned char, N> buf){
    static_assert(N==20 || N==30, "invalid value of N");
    std::cout << N << "-" << buf.size() << std::endl;
    return 0;
}

It will cause a compile time error for invalid values of N. See it live.

Upvotes: 3

Related Questions