Search code examples
c++templatesargumentspass-by-value

Why I can't pass string literal to this template?


Here is a template

template <int LEN_1, int LEN_2>
bool less (char const (*arr1)[LEN_1], char const (*arr2)[LEN_2]) {
    for (int i=0; i<LEN_1 && i<LEN_2; ++i) {
        if (arr1[i]<arr2[i]) return true;
        if (arr1[i]>arr2[i]) return false;
    }
    return LEN_1 < LEN_2;
}

I am trying to pass string literal as its arguments from main, like:

std::string a = "hello";
std::string b = "ok";

::less(a, b);

Based on what I know, string literal should be decayed to char const*, if I pass args by value. But it just can't pass the compilation.

Plz do me a favour to break this egg.


Solution

  • This is not legal C++. If you want arrays to decay, you have to pass size explicitly. Here's the syntax for it:

    bool less (char const *arr1, std::size_t LEN_1, char const *arr2, std::size_t LEN_2) {
        for (std::size_t i=0; i<LEN_1 && i<LEN_2; ++i) {
            if (arr1[i]<arr2[i]) return true;
            if (arr1[i]>arr2[i]) return false;
        }
        return LEN_1 < LEN_2;
    }
    

    But you seem to want to pass the array by reference. Here's how you do it:

    template <std::size_t LEN_1, std::size_t LEN_2>
    bool less (char const (&arr1)[LEN_1], char const (&arr2)[LEN_2]) {
        for (std::size_t i=0; i<LEN_1 && i<LEN_2; ++i) {
            if (arr1[i]<arr2[i]) return true;
            if (arr1[i]>arr2[i]) return false;
        }
        return LEN_1 < LEN_2;
    }
    

    Note the use of std::size_t instead of int.

    Alternatively, you can use null terminator instead of the size:

    bool less (char const arr1[], char const arr2[]) {
        for (/*nothing*/;*arr1 && *arr2; ++arr1, ++arr2) {
            if (*arr1 < *arr2) return true;
            if (*arr1 > *arr2) return false;
        }
        return !*arr1;
    }
    

    However, in your example, you are passing instances of std::string, not char arrays. In that case you don't need a custom function. Overloaded operator< does what you want. If you really want to use your function, use std::string::c_str:

    less(a.c_str(), b.c_str());
    

    Or you can pass the literals directly:

    less("hello", "ok");