How to pass const char[] array as constexpr template parameter using C++ STL library?


user

I have the following standard working code :C++ 17

template< int PathIndex, int PathLength, const char (path)[PathLength] >
constexpr const int findlastslash()
{
    if constexpr( PathIndex < 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
        return PathIndex;
    }
    else {
        return findlastslash<PathIndex - 1, PathLength, path>();
    }
}

template< int PathLength, const char (path)[PathLength] >
constexpr const int startfindlastslash()
{
    return findlastslash< PathLength - 1, PathLength, path >();
}

int main(int argc, char const *argv[]) {
    static constexpr const char path[7] = "c/test";
    static_assert( startfindlastslash< 7, path >() == 1, "Fail!" );
}

I want to stop writing/hardcoding the array size , i.e., make template metaprogramming infer the array size itself without having to write the size all over the place. For example, given something like the following:constexpr7constexpr const char[]

template< int PathIndex, int PathLength, const char (path)[PathLength] >
constexpr const int findlastslash()
{
    if constexpr( PathIndex < 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
        return PathIndex;
    }
    else {
        return findlastslash<PathIndex - 1, PathLength, path>();
    }
}

template< const char (path)[PathLength] >
constexpr const int startfindlastslash()
{
    return findlastslash< PathLength - 1, PathLength, path >();
}

template<int PathLength>
constexpr const char path[PathLength] = "c/test";

int main(int argc, char const *argv[]) {
    static_assert( startfindlastslash< path >() == 1, "Fail!" );
}

Of course, the above code is completely invalid. However, it is easy to describe things.

How will you solve this problem? Would you replace one or ?constexpr const char path[7] = "c/test";std::arraystd::string_view

I try to build this with the following code :std::string_view

#include <string_view>

template< int PathIndex, std::string_view path >
constexpr const int findlastslash()
{
    if constexpr( PathIndex < 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
        return PathIndex;
    }
    else {
        return findlastslash<PathIndex - 1, path>();
    }
}

template< std::string_view path >
constexpr const int startfindlastslash()
{
    return findlastslash< path.length() - 1, path >();
}

int main(int argc, char const *argv[]) {
    static constexpr std::string_view path{"c/test"};
    static_assert( startfindlastslash< path >() == 1, "Fail!" );
}

But it doesn't compile:

  1. g++ -o main.exe --std=c++17 test_debugger.cpp

    test_debugger.cpp:3:43: error: ‘class std::basic_string_view<char>’ is not a valid type for a template non-type parameter
     template< int PathIndex, std::string_view path >
                                               ^~~~
    test_debugger.cpp:14:28: error: ‘class std::basic_string_view<char>’ is not a valid type for a template non-type parameter
     template< std::string_view path >
                                ^~~~
    test_debugger.cpp: In function ‘int main(int, const char**)’:
    test_debugger.cpp:22:47: error: no matching function for call to ‘startfindlastslash<path>()’
         static_assert( startfindlastslash< path >() == 1, "Fail!" );
                                                   ^
    test_debugger.cpp:15:21: note: candidate: template<<typeprefixerror>path> constexpr const int startfindlastslash()
     constexpr const int startfindlastslash()
                         ^~~~~~~~~~~~~~~~~~
    test_debugger.cpp:15:21: note:   template argument deduction/substitution failed:
    test_debugger.cpp:22:47: note: invalid template non-type parameter
         static_assert( startfindlastslash< path >() == 1, "Fail!" );
                                                   ^
    
  2. clang++ -Xclang -ast-print -fsyntax-only --std=c++17 test_debugger.cpp > main.exe

    test_debugger.cpp:3:43: error: a non-type template parameter cannot have type 'std::string_view' (aka 'basic_string_view<char>')
    template< int PathIndex, std::string_view path >
                                              ^
    test_debugger.cpp:14:28: error: a non-type template parameter cannot have type 'std::string_view' (aka 'basic_string_view<char>')
    template< std::string_view path >
                               ^
    test_debugger.cpp:15:21: error: no return statement in constexpr function
    constexpr const int startfindlastslash()
                        ^
    test_debugger.cpp:22:20: error: no matching function for call to 'startfindlastslash'
        static_assert( startfindlastslash< path >() == 1, "Fail!" );
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~
    test_debugger.cpp:15:21: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'path'
    constexpr const int startfindlastslash()
                        ^
    4 errors generated.
    

Note: I'm not interested in the last slash of the string during the execution of the algorithm. I'm just using this silly example as an excuse to better learn what you can and can't do with constexpr template parameters.

For reference, an example of a (C++20) string literal as a non-type template parameter? I found this sample code using : ( https://godbolt.org/z/L0J2K2 ) to do some cool stuffC++ 20

template<unsigned N>
struct FixedString {
    char buf[N + 1]{};
    constexpr FixedString(char const* s) {
        for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
    }
    constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;

template<FixedString T>
class Foo {
    static constexpr char const* Name = T;
public:
    void hello() const;
};

int main() {
    Foo<"Hello!"> foo;
    foo.hello();
}

Do I really need to define my own class? Is there anything that (Standard Template Library) can be used to replace this common/simple task?FixedStringC++ STL

For reference, I found this nice related 3rd party library:

  1. https://github.com/irrequietus/typestring . _C++11/14 strings for direct use in template parameter lists, template metaprogramming
  2. https://github.com/hanickadot/compile-time-regular-expressions A Compile time PCRE (almost) compatible regular expression matcher.
Jarrod 42

I want to stop writing/hardcoding constexpr array size 7

In C++17 you can use it autoas a non-template parameter and get rid of hardcoding 7:

template <std::size_t PathIndex, const auto& path>
constexpr std::size_t findlastslash()
{
    if constexpr (PathIndex < 1 || path[PathIndex] == '/' || path[PathIndex] == '\\') {
        return PathIndex;
    }
    else {
        return findlastslash<PathIndex - 1, path>();
    }
}

template <const auto& path>
constexpr std::size_t startfindlastslash()
{
    return findlastslash<std::extent_v<std::remove_reference_t<decltype(path)>> - 1, path >();
}

int main() {
    static constexpr const char path[] = "c/test";
    static_assert(startfindlastslash<path>() == 1, "Fail!" );
}

demo version

You can "protect" it autousing SFINAE or concepts (C++20) :

template <typename T, std::size_t N>
constexpr std::true_type is_c_array_impl(const T(&)[N]) { return {}; }

template <typename T>
constexpr std::false_type is_c_array_impl(const T&) { return {}; }

template <typename T>
constexpr auto is_c_array() -> decltype(is_c_array_impl(std::declval<const T&>())) {return {};}

template <typename T>
concept CArrayRef = (bool) is_c_array<const T&>() && std::is_reference_v<T>;

template <std::size_t PathIndex, const auto& path>
constexpr std::size_t findlastslash() requires (CArrayRef<decltype(path)>)
{
    if constexpr (PathIndex < 1 || path[PathIndex] == '/' || path[PathIndex] == '\\') {
        return PathIndex;
    }
    else {
        return findlastslash<PathIndex - 1, path>();
    }
}

template <const auto& path>
constexpr std::size_t startfindlastslash() requires (CArrayRef<decltype(path)>)
{
    return findlastslash<std::extent_v<std::remove_reference_t<decltype(path)>> - 1, path >();
}

demo version

Do I really need to define my own FixedStringclass? Doesn't the C++ STL (Standard Template Library) have anything useful for this common/simple task?

It appears that there is currently no equivalent to FixedString.

Related


How to pass constexpr as template parameter?

Peter Bell I have a templated class MyClassthat I want to run against various parameters to measure some values. I know the exact parameters before compiling, so I figured there must be a way to achieve my goal. My code so far: template <int T> class MyClass {

How to pass constexpr as template parameter?

Peter Bell I have a templated class MyClassthat I want to run against various parameters to measure some values. I know the exact parameters before compiling, so I figured there must be a way to achieve my goal. My code so far: template <int T> class MyClass {

How to pass constexpr as template parameter?

Peter Bell I have a templated class MyClassthat I want to run against various parameters to measure some values. I know the exact parameters before compiling, so I figured there must be a way to achieve my goal. My code so far: template <int T> class MyClass {

How to pass constexpr as template parameter?

Peter Bell I have a templated class MyClassthat I want to run against various parameters to measure some values. I know the exact parameters before compiling, so I figured there must be a way to achieve my goal. My code so far: template <int T> class MyClass {

How to pass constexpr as template parameter?

Peter Bell I have a templated class MyClassthat I want to run against various parameters to measure some values. I know the exact parameters before compiling, so I figured there must be a way to achieve my goal. My code so far: template <int T> class MyClass {

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

How to pass const char* as parameter of LPCSTR parameter?

Gábor Marschall I want to use this function to call the PlaySoundA function, but the sound file I want to play doesn't open. void AudioClass::playAudio(const char* incomingData, const char* filePath) { char buffer[100]; // <- danger, only storage for 100

const char array with template parameter size vs char pointer

hard I saw the following types of constructs in some code today: template<unsigned int N> unsigned int f(const char (&a)[N]); Does it make any sense to have: unsigned int f(const char *a); I vaguely understand the meaning of pointer sharing in the latter, bu

const char array with template parameter size vs char pointer

hard I saw the following types of constructs in some code today: template<unsigned int N> unsigned int f(const char (&a)[N]); Does it make any sense to have: unsigned int f(const char *a); I vaguely understand the meaning of pointer sharing in the latter, bu

const char array with template parameter size vs char pointer

hard I saw the following types of constructs in some code today: template<unsigned int N> unsigned int f(const char (&a)[N]); Is there any plausible sense for the following reasons: unsigned int f(const char *a); I vaguely understand the meaning of pointer s

const char array with template parameter size vs char pointer

hard I saw the following types of constructs in some code today: template<unsigned int N> unsigned int f(const char (&a)[N]); Is there any plausible sense for the following reasons: unsigned int f(const char *a); I vaguely understand the meaning of pointer s

const char array with template parameter size vs char pointer

hard I saw the following types of constructs in some code today: template<unsigned int N> unsigned int f(const char (&a)[N]); Does it make any sense to have: unsigned int f(const char *a); I vaguely understand the meaning of pointer sharing in the latter, bu

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want

How to pass constexpr string array as parameter?

who I am I have a file that contains an array of strings representing some icons. static constexpr char icons1[2][40] = { "icon1_A", "icon1_B" }; static constexpr char icons2[3][30] = { "icon22_A", "icon2_B", "icons2_C" }; Then I have a class that I want