I'm creating a container that can be templated on the string type it uses for its members, either it's an owning or non-owning string (std::string
vs std::string_view
). For the case of the non-owning string, I can't supply an allocator and hence I have to convince the compiler to write a constructor that doesn't take an alloctor. Here's my current approach but I have yet multiple problems to solve:
#include <iostream>
#include <string_view>
#include <memory>
#include <string>
template <typename T>
concept uses_allocator_general = requires {
typename T::allocator_type;
};
template <typename StringType = std::string>
struct URL {
using allocator_type = std::conditional_t<uses_allocator_general<StringType>,
typename StringType::allocator_type, void>;
URL(allocator_type allocator = {})
: mystr{allocator}
{ }
StringType mystr;
};
int main() {
URL myurl;
URL<std::string_view> myurl_view;
}
StringType::allocator_type
is evaluated before std::conditional_t
. I would have to use some kind of indirection or SFINAE to retrieve the typedef conditionally.You can provide two constraint constructors for the two cases respectively
template <typename T>
concept uses_allocator_general = requires {
typename T::allocator_type;
};
template <typename StringType = std::string>
struct URL {
template<uses_allocator_general AllocStringType = StringType>
URL(AllocStringType::allocator_type allocator = {})
: mystr{allocator}
{ }
URL() requires (!uses_allocator_general<StringType>) = default;
StringType mystr;
};