C++20 Formatter Template Redefinition Error - c++

What I am trying to do: define two fmt::formatter templates, one for types that derive from std::exception and one for types that derive from std::array<char, N> so that I can pass these types as parameters to a logging function that uses fmt::format().
Problem: when I define only one of the formatter templates, everything works as expected, but when I define both, I get an error that states that I am redefining a type:
error: redefinition of ‘struct fmt::v7::formatter<T, char, void>’
Code sample:
template<typename T>
concept Exception = std::is_base_of_v<std::exception, T>;
template<std::size_t arrayLen>
template<typename T>
concept CharArray = std::is_base_of_v<std::array<char, arrayLen>, T>;
template <Exception T>
struct fmt::formatter<T> {
constexpr auto parse(format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const T& ex, FormatContext& ctx) {
return format_to(ctx.out(), "{}", ex.what());
}
};
template <CharArray T>
struct fmt::formatter<T> {
constexpr auto parse(format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const T& arr, FormatContext& ctx) {
const std::string str{arr.data(), strnlen(arr.data(), arr.size())};
return format_to(ctx.out(), "{}", str);
}
};
Dev environment: g++ 11.1.0, CentOS, fmt from <spdlog/fmt/bundled/format.h>
What I have tried: I tried defining the two concepts Exception and CharArray such that they are mutually exclusive. I have tried using a concept other than CharArray which is not templated on a size argument. I tested that having two void foo(T) functions, one templated on Exception and one on CharArray works as expected.
What I am looking for: At this point, I'm far more interested in an explanation about what I am doing incorrectly than I am in potential work-arounds. I have several work-arounds in mind if it comes to that, but I really want to figure out where my misunderstanding is so I can learn from it.
Thanks in advance for your help and please be kind in your responses.
Solution update: I was defining the CharArray concept incorrectly and it wasn't being caught by GCC. I also needed to move my templates inside the fmt namespace due to a GCC bug.

This:
template<std::size_t arrayLen>
template<typename T>
concept CharArray = std::is_base_of_v<std::array<char, arrayLen>, T>;
is not a valid declaration. I'm surprised the compiler does not flag that as being obviously ill-formed (reported as 102289).
You only get one template head for a concept (the only place you can write multiple such template declarations is when you're defining member function templates of class templates outside of the class body, or other things like that).
The way you can write this concept in C++20 is:
template <std::size_t N>
void f(std::array<char, N> const&);
template <typename T>
concept CharArray = requires (T t) { f(t); }
Basically, if you can call f(t) with a T, then that means that t either is some kind of std::array<char, N> or inherits from one. With additional lambda features in C++20, we can even put that into the concept itself:
template <typename T>
concept CharArray = requires (T t) {
[]<std::size_t N>(std::array<char, N> const&){}(t);
};
The lambda here just exists to do that same "is callable" check that we did with the free function template.

Related

How to decltype template method C++?

I write interfaces through concepts for implementation validation.
There are no problems with conventional methods:
// Interface realization
struct Realization
{
int* TestMethod(const std::string& aStr)
{
return (int *) aStr.c_str();
}
};
// Concept
template <typename T>
concept IRealization = std::is_same_v<decltype(&T::TestMethod), int* (T::*)(const std::string&)>;
// and then, for example
void Check()
{
static_assert(IRealization<Realization>)
}
but when I try to write a similar check for a template method:
// Interface realization
struct Realization
{
template <typename T>
int* TemplateMethod(const T& aStr)
{
return (int *) aStr.c_str();
}
};
, I run into a problem of dectype a template method, because I cant write
decltype(&RealizationImpl::TemplateMethod)
(at the time of checking the interface, I do not know the type that will be substituted)
Please tell me, can I somehow get the signature of the template function without type, or otherwise solve my problem? Thanks!
You should not write concepts like this. A concept should never check for something as specific as a member function with an exact signature. A concept should instead say that, given an instance of the type in question, I should be able to do i.memberFunc(...), where ... is the list of parameters.
For example, your "IRealization" concept (please don't prefix concepts with I. Concepts are not interfaces) ought to say "T must have a member function which can be called given a std::string argument and results in something which is convertible to an int." That would look like:
template <typename T>
concept IRealization = requires(T t, std::string str)
{
{ t.TestMethod(str) } -> convertible_to<int>;
};
This allows the user to provide a TestMethod that takes, for example, std::string_view instead of std::string. There's no point in being so incredibly restrictive on the type.
A concept that checks for T having a member function which is callable with some type U would have to be templated on both T and U:
template <typename T, typename U>
concept IRealization = requires(T t, U u)
{
{ t.TestMethod(u) } -> convertible_to<int>;
};
What is the problem with adding another type to the concept?
// Concept
template <typename T, typename U>
concept IRealization = std::is_same_v<decltype(&T::template TestMethod<U>), int* (T::*)(const U&)>;
For instance.
You could even make it prettier by creating a typedef -
template<typename T, typename U>
using FuncT = decltype(&T::template TestMethod<U>);

Enable a template depending on whether a certain function exists

I would like to design a template that automatically provides an operator<<(std::ostream&, const T&) for all classes T for which T::print_to(std::ostream&) exists and can be called, so that I can define the printing function as a member function (and, in particular, take advantage of virtual calls).
Through trial and error, I managed to arrive at this:
template<typename T, typename = decltype(std::declval<T>().print_to(std::declval<std::ostream&>()))>
std::ostream &operator<<(std::ostream &s, const T &t) {
t.print_to(s);
return s;
}
It seems to be working, but since I am still new to SFINAE and this kind of tricks, would like to know if there is any pitfall or enhancement that can be made. I put a small test bench at https://ideone.com/uLJxac.
If possible, I would like to have a C++14 solution, because I am working with a C++14 code base. However, if using C++17 allows for a better solution, than I am also interested to that one.
It seems to me that your applying SFINAE correctly in your operator<<(); I don't see pitfalls in your solution.
I propose another version (C++11 compatible, so also C++14) just because require less typewriting
template <typename T>
auto operator<< (std::ostream & s, T const & t)
-> decltype( t.print_to(s), s )
{
t.print_to(s);
return s;
}
Edit:
There is no pitfall with your code, sorry about that. But this answer enables you to write code more like C++20 concept:
template <class T>
auto& operator << (std::ostream &out, const printable_t<T> &t)
{
t.print_to(out);
return out;
}
In fact, I wrote a C++17 concept_check library based on detector and can be used in this way.
For more info on concept support in C++20, have a look at these 2:Constraints and concepts (since c++20) and Constraints and concepts (TS)
Original answer:
std::experiment::is_detector can do the magic for you. Though it is not in standard library, it is not difficult to implement and that link gives the suggested implementation.
Here I will give you how to detect that function along with my implementaion of is_detected_v.
#include <type_traits>
#include <utility>
#include <ostream>
// For support for C++17 is not complete in many compiler, I also define void_t
template <class...> using void_t = void;
namespace impl {
template <class Default, class AlwaysVoid, template <class...> class Op, class ...Args>
struct detector: private std::false_type
{
using std::false_type::value;
using type = Default;
};  
template <class Default, template <class...> class Op, class ...Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>: private std::true_type
{
using std::true_type::value;
using type = Op<Args...>;
};
} // namespace impl
struct nonsuch {};
#define CONCEPT_T constexpr const static inline bool
template <template<class...> class Op, class ...Args>
CONCEPT_T is_detected_v = impl::detector<nonsuch, void, Op, Args...>::value;
// Detect whether print_to exists.
template <class T>
using print_to_ret_t = decltype( std::declval<T>().print_to( std::declval<std::ostream&>() ) );
template <class T>
CONCEPT_T has_func_print_to_v = is_detected_v<print_to_ret_t, T>;
template <class T, std::enable_if_t< has_func_print_to_v<T> >>
using printable_t = T;
#undef CONCEPT_T
You can try to add C++14 support to this code. It won't be too difficult. The CONCEPT_Tmust be changed to constexpr const static bool to adjust to C++14.

Why does decltype return type fail for recursive template, while return type deduction works just fine?

While working on a C++11 type-set, I tried to implement this function (stripped down to the minimum):
constexpr auto test() -> bool;
template <typename T, typename... Rest>
constexpr auto test() -> decltype(test<Rest...>())
{
return {};
}
Both gcc and clang choke on this. Clang says:
test.cpp:54:40: error: 'Rest' does not refer to a value
constexpr auto test() -> decltype(test<Rest...>())
^
gcc complains:
test.cpp:54:44: error: expected primary-expression before ‘...’ token
constexpr auto test() -> decltype(test<Rest...>())
I guess this is because the variadic version of test is not even fully declared when the decltype looks at it.
However, when I use return type deduction in C++14, this compiles just fine:
constexpr auto test() -> bool;
template <typename T, typename... Rest>
constexpr auto test()
{
return test<Rest...>();
}
Seems like test is considered sufficiently declared here.
I wonder why this doesn't work for the decltype variant? Even if I turn on C++14 support?
PS: It turns out, that I cannot really call even the C++14 function, so maybe the whole thing is botched...
One problem is that your first test overload is not a function template, so can't be called with test<>() syntax.
However, decltype doesn't really work with recursive variadic functions like that, since the return type is part of the declaration of the function, so that overload is not declared when the name is looked up.
You can get around this in C++11 by using template classes instead:
template <typename... Ts>
struct test;
template <typename T, typename... Ts>
struct test<T,Ts...> {
static decltype(test<Ts...>::value()) value() { return test<Ts...>::value(); }
};
template <>
struct test<> {
static bool value() { return true; }
};
Live demo
In C++14 you can make the first overload take a single template parameter and the second take two and a parameter pack:
template <typename T>
constexpr auto test() -> bool { return true; }
template <typename T, typename U, typename... Rest>
constexpr auto test()
{
return test<U,Rest...>();
}
Live demo
While the template function itself is being declared, the template function itself has not been declared. So it is not visible to the trailing return type decltype.
You can fix this with ADL. If your template function takes an argument from the same namespace as your template function, the lookup for the return type becomes willing to look at the template function itself. This is because templates do lookup for their return type signature using both the context just before they where declared, and using ADL on each of the parameters.
template<class...Ts> struct types {};
namespace bob{
struct mytag{};
constexpr auto test(mytag, types<>) -> bool{ return true; }
template <typename T, typename... Rest>
constexpr auto test(mytag, types<T,Rest...>)
-> decltype( test( mytag{}, types<Rest...>{} ) )
{
return test(mytag{},types<Rest...>{});
}
}
template<class...Ts>
constexpr auto test()
->decltype( bob::test( bob::mytag{}, types<Ts...>{} ) ){
return bob::test( bob::mytag{}, types<Ts...>{} );
}
You may need constexpr types(){}; and similar for mytag depending on compiler.
This also fixes the fact that test<> is illegal in your original code. Functions do much better with types passed by (tag template wrapped) value in my experience. Overloading is more friendly.

Disallow function template instantiation with iterator parameter

I have a function template which takes a templated parameter:
template <class R>
RefT<R> make_ref(R& res) {
return RefT<R>(&res);
}
I either want to prevent R from being any kind of iterator, or, if this is easier, I want to have a overload that the compiler will prefer to use for iterators which calls make_ref again with the iterator dereferenced.
Best approach would be combining the two, so the compiler prefers using iterator specific overload, and refuses to use the non-specific version.
I would like consumers of the code to be able to call make_ref(something) without having to think about whether the something is an iterator or not - I just need to do something different if it is, and if that's not possible, give a useful error message to the consumer.
First the traits (you may have to tweak it with your requirements):
template <typename T>
auto is_iterator_impl(T* it)
-> decltype(**it, ++(*it), (*it) == (*it), std::true_type());
template <typename T>
auto is_iterator_impl(...) -> std::false_type;
template <typename T>
using is_an_iterator = decltype(is_iterator_impl<T>(0));
Note: using std::iterator_traits<IT> may be a good alternative.
With SFINAE, you may do
template <class R>
std::enable_if_t<!is_an_iterator<R>::value, RefT<R>>
make_ref(R& res) {
return RefT<R>(&res);
}
template <class R>
std::enable_if_t<is_an_iterator<R>::value && !std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
template <class R>
std::enable_if_t<std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
Note: as you want to manage pointer differently, I also use std::is_pointer in addition to the custom is_an_iterator.
Note: The conditions should not have overlap, else you have conflict.
Live Demo
I used is_iterator from here: https://stackoverflow.com/a/4336298/678093
This traits struct is used with SFINAE to only enable make_ref for non-iterator types:
#include <type_traits>
template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer
static const bool value = sizeof(test(makeT())) == sizeof(void *);
};
// just to make it compile
template <typename R>
struct RefT{};
template <class R, typename std::enable_if<!is_iterator<R>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
int main()
{
int* a;
make_ref(a); // fails to compile
int b;
make_ref(b); // compiles once RefT is correct
return 0;
}
An alernative solution is to use std::iterator_traits:
template <class R, typename std::enable_if<std::is_same<typename std::iterator_traits<R>::value_type, void>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
This could also be done by using SFINAE with std::iterator_traits, would handle all cases that previous answers handle (pointers and types having internal iterator_category typedef) but:
no need to write your own traits (like is_iterator) to do this, or at least most of the template machinery is encapsulated in iterator_traits
could also handle potential user defined iterators that were having their own iterator_traits specialization without using the generic iterator_category typedef, not sure if this relevant/legal technique but definitely possible

SFINAE technique for free function wrappers

I would really like to be able to have a free function that adapts to whatever types its being given.
e.g.
template <typename T> bool ReadLine(T & reader, std::string & line)
{
return reader.ReadString(line);
}
For some T, the correct function is reader.ReadString(buffer). But for others, it should be reader.ReadLine(buffer). And of course, there may be other patterns in the future. The point being to adapt the free function ReadLine(from, into) to work with any reasonable set of from & into (I've forced the destination buffer to be a std::string to simplify things here).
Now, I can make a non-template version of ReadLine for any concrete type I want, but what I really need is the ability to partially specialize for classes of types, such that those which support the pattern reader.ReadString() all end up using that, and those which support reader.ReadLine() use that, and in the future I can add other patterns without disturbing anything that already works.
I'm aware that I can create a policy class, such as LineReaderPolicy, which knows for a given T which pattern to use (it would have to be partially specialized depending on T to map it to the correct pattern.
But is there a better, more C++14 way of solving this?
This is one of those "God it seems that templates are really, really close to being really, really useful... but for this constantly recurring problem..."
Compostability is better than ever with C++11/14, but it still seems that this fundamental problem is unsolved? Or is it?!
How would you suggest I write a set of free functions that adapt to any reasonable T to read a line from it? Whether T be a string stream, an output iterator, a file handle, a string, a string-view, etc., etc...
I just cannot think that C++ is really come of age until I can write a reasonable
template <typename T> size_t length(T t) { return t.size(); }
For which I can then extend that into any reasonable T, and stop having to write code that know so many details of T, but can inter-operate with tons of Ts via such flexible free function adapters...
If you can ensure that at most one of reader.ReadString or reader.ReadLine is defined, use SFINAE to control overloading (Live at Coliru):
template <typename T>
auto ReadLine(T& reader, std::string& line) -> decltype(reader.ReadString(line)) {
return reader.ReadString(line);
}
template <typename T>
auto ReadLine(T& reader, std::string& line) -> decltype(reader.ReadLine(line)) {
return reader.ReadLine(line);
}
The inapplicable implementation will trigger SFINAE and be removed from the overload set, leaving only the correct implementation.
In C++14 you'll be able to omit the trailing return type and simply use return type deduction.
In a future revision of C++, Concepts Lite will enable this to be done more cleanly. Given concepts that discriminate the two different kinds of readers - say StringReader and LineReader:
template <typename T>
concept bool StringReader() {
return requires(T& reader, std::string& line) {
{reader.ReadString(line)} -> bool;
};
}
template <typename T>
concept bool LineReader() {
return requires(T& reader, std::string& line) {
{reader.ReadLine(line)} -> bool;
};
}
you'll be able to directly constrain your implementations to the set of types that model those concepts:
bool ReadLine(StringReader& reader, std::string& line) {
return reader.ReadString(line);
}
bool ReadLine(LineReader& reader, std::string& line) {
return reader.ReadLine(line);
}
Hopefully you'll be able to reuse those concepts elsewhere to justify the "new-special-better" syntax being substantially longer than the old nasty syntax. Concepts Lite also will make it possible to handle types that model both concepts by explicit disambiguation:
template <typename T>
requires StringReader<T>() && LineReader<T>()
bool ReadLine(T& reader, std::string& line) {
// Call one, or the other, or do something completely different.
}
I just cannot think that C++ is really come of age until I can write a reasonable
template <typename T> size_t length(T t) { return t.size(); }
For which I can then extend that into any reasonable T, and stop having to write code that know so many details of T, but can inter-operate with tons of Ts via such flexible free function adapters...
You want Concepts Lite, which I hope will arrive in C++17:
template<typename T>
concept bool Has_size()
{
return requires(T t) {
t.size() -> Integral;
};
}
template<typename T>
concept bool Has_length()
{
return requires(T t) {
t.length() -> Integral;
};
}
template <Has_size T> auto length(T t) { return t.size(); }
template <Has_length T> auto length(T t) { return t.length(); }
Until then you can use SFINAE to emulate it, which can be done in many ways, the tersest for your example is probably just a trailing-return-type as shown in Casey's answer.
template <typename T>
auto length(T t) -> decltype(t.size()) { return t.size(); }
template <typename T>
auto length(T t) -> decltype(t.length()) { return t.length(); }
template<typename>struct type_sink{typedef void type;};
template<typename T>using TypeSink=typename type_sink<T>::type;
template<typename T,typename=void>
struct has_x:std::false_type{};
template<typename T>
struct has_x<T,TypeSink(decltype(std::declval<T>().x())>:std::true_type{};
is a pretty simple traits class for 'does a type have a .x() method, and can be generalized.
We can then use tag dispatching to direct our function to custom implementations.
template<typename T>
bool do_x_helper(T&t, std::true_type ){
return t.x();
}
template<typename T>
bool do_x_helper(T7, std::false_type ){
// alternative
}
template<typename T>
bool do_x(T& t){
return do_x_helper( t, has_x<T>() );
}
This technique lets you have complex tests and method bodies. You basically have to do overload resolution and dispatching manually, but it gives you full control. It is similar to the techniques that std algorithms use to dispatch iterator types: in that case more than just true_type and false_type is dispatched on.