2

Is it possible to tell a const char array that does not ends with '\0' apart from a C-style string in compile time?

Say I want to write two constructors for a class.

One constructor constructs from a C-style string, which ends with '\0'.

The other constructor, with different behavior, constructs from a const char array that does not ends with '\0'.

As a minimal example, consider

#include <cstddef>
#include <iostream>

struct Foo
{
    Foo(const char *)
    {
        std::cout << "a C-style string" << std::endl;
    }

    // Question: How to modify Foo so that a const char array that does not
    //           ends with '\0' will go to a different constructor?
    template<size_t N>
    Foo(const char (&)[N])
    {
        std::cout << "a const char array "
                     "that does not ends with '\\0'" << std::endl;
    }
};

int main()
{
    Foo("a C-style string");          // print "a C-style string"

    const char a[3] {'a', 'b', 'c'};
    Foo foo(a);                       // print "a C-style string" - can it change?

    return 0;
}

Compiled with g++ -std=c++17.

Question: Is there any way to achieve this?

Maybe I could apply SFINAE techniques but I haven't figured out how to do so.

Note: There are currently several similar but not identical questions on StackOverflow. I didn't find one that directly addresses my question.

aafulei
  • 2,085
  • 12
  • 27

2 Answers2

2

No, it is impossible in that way. Non-template functions are more preferable while overload resolution. C++ template functions overload resolution

Nontemplate functions are first-class citizens.

Why does overload of template and non-template function with the “same signature” call the non-template function?

When a template function and a non-template function are both viable for resolving a function call, the non-template function is selected.

Possible workaround:

struct Foo
{
    void Cstr(const char *)
    {
        std::cout << "a C-style string" << std::endl;
    }

    template<size_t N>
    Foo(const char (&s)[N])
    {
        if (N > 0 && !s[N - 1])
            Cstr(s);
        else
            std::cout << "a const char array "
                         "that does not ends with '\\0'" << std::endl;
    }
};
273K
  • 29,503
  • 10
  • 41
  • 64
1

one interesting thing is, if removing const in array declaration, it goes with the array constructor

#include <cstddef>
#include <iostream>

struct Foo
{
    Foo(const char *)
    {
        std::cout << "a C-style string" << std::endl;
    }

    template<size_t N>
    Foo(const char (&)[N])
    {
        std::cout << "a const char array "
                     "that does not ends with '\0'" << std::endl;
    }
};

int main()
{
    Foo("a C-style string");

    // const char a[3] {'a', 'b', 'c'};
    char a[3] {'a', 'b', 'c'};
    Foo foo(a);

    return 0;
}
delta
  • 3,778
  • 15
  • 22
  • Thank you for the observation. That is right, but that changes the user code, thus not a real solution. – aafulei Jul 14 '20 at 03:20
  • yes, I just pop out the observation, to see if anyone could explain, which may lead to a proper solution – delta Jul 14 '20 at 03:51