0

Note:
I heavily changed my question to be more specific, but I will keep the old question at end of the post, in case it is useful to anyone.

New Question

I am developing an embedded application which uses the following types to represent strings :

  1. string literals(null terminated by default)
  2. std::array<char,size> (not null terminated)
  3. std::string_view

I would like to have a function that accepts all of them in a uniform way. The only problem is that if the input is a string literal I will have to count the size with strlen that in both other cases doesn't work but if I use size it will not work on case 1.

Should I use a variant like so: std::variant<const char *,std::span<char>> ? Would that be heavy by forcing myself to use std::visit ? Would that thing even match correctly all the different representations of strings?

Old Question

Disclaimer when I refer to "string" in the following context I don't mean an std::string but just an abstract way to say alphanumeric series.

Most of the cases when I have to deal with strings in c++ I use something like void func(const std::string &); or without the const and the reference at some cases.Now on an embedded app I don't have access to std::string and I tried to use std::string_view the problem is that std::string_view when constructed from a non literal sometimes is not null terminated Edit: I changed the question a bit as the comments implied some very helphull hints . So even though y has a size in the example below:

std::array<char,5> x{"aa"} ;
std::string_view  y(x.data());

I can't use y with a c api like printf(%s,y.data()) that is based on null termination

#include <array>
#include <string_view>
#include "stdio.h"
int main(){
    std::array<char,5> x{"aaa"};
    std::string_view y(x.data());
    printf("%s",x);
}

To summarize:
What can I do to implement a stack allocated string that implicitly gets a static size at its constructors (from null terminated strings,string literals, string_views and std::arrays) and it is movable (or cheap copyable)?
What would be the underlying type of my class? What would be the speed costs in comparison with the underlying type?

jeb
  • 78,592
  • 17
  • 171
  • 225
Spyros Mourelatos
  • 484
  • 1
  • 8
  • 19
  • 2
    What's wrong with `std::array x{"aa"} ;std::string_view(x.data());`? [It works fine here](http://coliru.stacked-crooked.com/a/714dae093f3527c0) – NathanOliver Dec 02 '20 at 13:39
  • understanding code described in english is very difficult. Also, as you don't know a solution yet, your description quite likely misses to explain the part that is essential for the problem. Can you show a [mcve] that highlights whatever problem you encounter with `std::array x{"aa"} ;std::string_view(x.data());` ? – 463035818_is_not_an_ai Dec 02 '20 at 13:44
  • 1
    I cannot get what you mean by movable? `std:: string_view` is what its name implies; a const view on abstract string. And as a view, it is copiable. `std::span` can be used as a mutable alternative - yet as a reference viewing the original.But deep copy of the underlying string cannot be carried on with automatic storage. On an embedded system you may use `std::basic_string` with custom allocator - instead of `std::string`. – Red.Wave Dec 02 '20 at 13:54
  • 1
    `string_view` has a constructor that takes a pointer and a size. – Marshall Clow Dec 02 '20 at 14:09
  • I'v not grasped the Q yet; U need a modifiable string or just deal with string literals? Can U provide a minimal use case example? – Red.Wave Dec 02 '20 at 21:09
  • 1
    Is this explicitly about NOT overloading your function for each of the three cases in the list? Otherwise that seems to be the obvious solution. – Yunnosch Dec 07 '20 at 08:52
  • @SpyrosMourelatos Are you aware of the mechanisms of function overloading in C++? – KamilCuk Dec 07 '20 at 09:16
  • Can't see the relevance to the *embedded* tag – jeb Dec 07 '20 at 09:46

1 Answers1

2

I think that you are looking at two largely and three subtly different semantics of char*.

Yes, all of them point at char but the type-specific info on how to determine the length is not carried by that. Even in the ancient ancestor of C++ (not saying C...) a pointer to char was not always the same. Already there pointers to terminated and non-terminated sequences of characters could not be mixed.

In C++ the tool of overloading a function exists and it seems to be the obvious solution for your problem. You can still implement that efficiently with only one (helper) function doing the actual work, based on an explicit size information in a second parameter.
Overload the function which is "visible" on the API, with three versions for the three types. Have it determine the length in the appropriate way, then call the single helper function, providing that length.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • it is so simple , I love it. What happens if I have a lot of functions which need the 3 overloads, can I avoid the bloat?Also what about two overloads with std::span? – Spyros Mourelatos Dec 07 '20 at 09:55
  • 1
    My pleasure. Actually I was expecting to have to add code details. Now it seems you only overlooked something you are already familiar with. Happens to everybody. Have fun. – Yunnosch Dec 07 '20 at 09:57
  • 1
    I think there might be something with policies/traits. But that is beyond my expertise. One thing would of course be to do the size determining in three helper functions. That at least reduces the repeated code. – Yunnosch Dec 07 '20 at 09:59