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.
Related
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.
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>);
For example, I want to implement my own generic sort function, I want to require the type that would be passed in to be Indexable, and the element inside would be Comparable
template <typename Cont>
**type_check: Cont is Indexable, Cont::Element is Comparable**
void my_sort(Cont& cont){
// do sorting work
}
When I do my_sort(vector<int>{1,6,5,4}) would be okay
But when do my_sort(linkedlist<int>{1,6,5,4}) would fail me at Compile/Runtime, because linkedlist is not Indexable.
So is there a way to do such kind of type contract programming?
P.S. I am in C++ 11 environment, but any Solution in later version of C++ is also welcomed
With SFINAE you can do something like:
template <typename Cont>
auto my_sort(Cont& cont)
-> decltype(cont[42], // Indexable
void(), // That void to avoid evil overload of operator comma
std::declval<Cont::Element>() < std::declval<Cont::Element>(), // Comparable
void()) // That final void for the return type of sort
{
// do sorting work
}
std::enable_if is an alternative (to the decltype) if you have the traits ready.
As mentioned in the comments, once the Concepts TS makes its way into the C++ standard, you'll be able to do this with something like:
template <typename T>
concept Sortable = requires(T t) {
{ t[0] < t[0] } -> bool
};
template <Sortable Cont>
my_sort(Cont& cont) {
// do sorting work
}
Live Demo
An older version of the Concepts TS is implemented by GCC with the -fconcepts flag, but it won't be in the standard until C++20. Until then, you can make do with SFINAE tricks:
template <typename Cont>
std::enable_if_t<std::is_convertible_v<decltype(std::declval<Cont>()[0] < std::declval<Cont>()[0]), bool>>
my_sort(Cont& cont) {
// ...
}
This will fail to compile if, for a given Cont c, c[0] < c[0] is either not valid or not convertible to bool.
Live Demo
I am designing an utility header that pumps binary data off an sf::InputStream. For ease of use, is comprises a single function name, readFromStream, that has a lot of (templated and non-templated) overloads for automatically deserializing standard-layout types and type compounds like vectors, tuples and my custom-designed grid class. The complete implementation can be found here: https://github.com/JoaoBaptMG/ReboundTheGame/blob/master/MainGame/utility/streamCommons.hpp
So, I have defined an overload readFromStream that pumps out a vector of any type by calling readFromStream again recursively:
template <typename T, typename std::enable_if<!is_optimization_viable<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, std::vector<T> &value)
{
size_t size;
if (!readFromStream(stream, VarLength(size)))
return false;
std::vector<T> newVal(size, T());
for (auto &val : newVal)
if (!readFromStream(stream, val))
return false;
newVal.swap(value);
return true;
}
I'd like to write an optimized version for standard-layout classes for that there's not an overload for readFromStream, so we can exploit the memory layout of them and blit them in a single read call:
// trait is_optimization_viable is what I'm having trouble to write
template <typename T, typename std::enable_if<is_optimization_viable<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, std::vector<T> &value)
{
size_t size;
if (!readFromStream(stream, VarLength(size)))
return false;
std::vector<T> newVal(size, T());
if (stream.read(newVal.data(), size*sizeof(T)) != size*sizeof(T))
return false;
newVal.swap(value);
return true;
}
Well, I could use a solution described on other answers to detect presence of a function, but there's a catch. When the type is standard-layout, I have a default readFromStream that reads like this:
template <typename T, typename std::enable_if<std::is_standard_layout<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, T& value)
{
return stream.read((void*)&value, sizeof(T)) == sizeof(T);
}
So, there's always a function that does the serialization, not just the one I wanted. The problem I want to solve here is: how can I detect the presence of a non-default readFromString for type T, in order to disable the optimized version of readFromString for std::vector<T>?
I have tried to pull a few tricks. I can't limit the optimization to POD types because I'm using sf::Vector2<T> on some types I want to deserialize, which is not POD. I tried to compare the function addresses I get when I use a non-templatized and templatized function, like:
using FPtr = bool(*)(sf::InputStream&, T&);
return (FPtr)readFromStream == (FPtr)readFromStream<T>;
But, strangely enough, it didn't work. And I researched a lot of solutions, but none I could adapt to what I needed. Maybe it's not possible in C++, and I'll have to resort "marking" the types I don't want to be optimized. Or maybe it's some obscure template I haven't thought of. How could I do this?
As I understand it your problem is:
is_optimization_viable<T>;
could be defined by:
template<typename T>
using is_optimization_viable<T> = std::is_standard_layout<T>;
but for the fact that, for certain values of T that are standard layout
you nonetheless require a custom bool readFromStream(sf::InputStream &stream, T &value),
overload which means they are not optimization-viable.
Well as you must write these custom overloads, you know what those
exceptional values of T are. Say they are types X, Y, Z.
Then you can define the trait as:
#include <type_traits>
template<typename T, typename ...Us>
struct is_one_of;
template<typename T>
struct is_one_of<T> {
static constexpr bool value = false;
};
template<typename T, typename First, typename ...Rest>
struct is_one_of<T,First,Rest...> {
static constexpr bool value =
std::is_same<T,First>::value || is_one_of<T,Rest...>::value;
};
// ^ C++17: `std::disjunction` does the job
template<typename T>
using has_custom_read_from_stream = is_one_of<T,X,Y,Z>;
template<typename T>
struct is_optimization_viable {
static constexpr bool value = std::is_standard_layout<T>::value &&
!has_custom_read_from_stream<T>::value;
};
I appreciate that you'd rather avoid the ongoing maintenance of the
hard-coded type-list X, Y, Z, and prefer somehow to SFINAE-probe
whether a call readFromStream(s, t) will be a call to one of the
custom overloads for some std::declval-ed s and t.
But that's a mirage. You tell us, there will be some overload
readFromStream(s, t) that will compile whatever the type of t.
If so, a SFINAE probe will always tell you that Yes, readFromStream(s, t)
will compile - for any T as the unqualified type of t. And you
still have to make a compiletime decision as to whether T is one of
the custom types, and if not, whether it is standard-layout.
That's all there is to the problem. To tell whether T is one of
the custom types you must either test it for identity with any one
of them disjunctively, as shown, or your must find a trait independent of their
identities that is satisfied by all and only the custom types. As you
don't tell us what those custom types are, I can't suggest any such trait,
but if you find one then it will define or replace has_custom_read_from_stream<T>.
Incidentally, I second #NirFriedman's comment: is std::standard_layout really what you mean?
Hello guys (and happy new year!)
I'm writing a (not really) simple project in C++ (my first, coming from plain C). I was wondering if there is a way to simplify the definition for multiple functions having the same template pattern. I think an example would be better to explain the problem.
The context
Let's assume I have a "Set" class which represents a list of numbers, defined as
template <class T>
class Set {
static_assert(std::is_arithmetic<T>(), "Template argument must be an arithmetic type.");
T *_address;
...
}
So if I have an instance (say Set<double>) and an array U array[N], where U is another arithmetic type and N is an integer, I would like to be able to perform some operations such as assigning the values of the array to those of the Set. Thus I create the function template inside the class
template <class U, int N>
void assign(U (&s)[N]) {
static_assert(std::is_arithmetic<U>(), "Template argument must be an arithmetic type.");
errlog(E_BAD_ARRAY_SIZE, N == _size);
idx_t i = 0;
do {
_address[i] = value[i];
} while (++i < size);
}
The problem
As far as my tests went the code above works perfectly fine. However I find it REALLY REALLY ugly to see since I need the static_assert to ensure that only arithmetic types are taken as arguments (parameter U) and I need a way to be sure about the array size (parameter N). Also, I'm not done with the assign function but I need so many other functions such as add, multiply, scalar_product etc. etc.!
The first solution
I was wondering then if there is a prettier way to write this kind of class. After some work I've come up with a preprocessor directive:
#define arithmetic_v(_U_, _N_, _DECL_, ...) \
template <class U, idx_t N> _DECL_ \
{ \
static_assert(std::is_arithmetic<U>(),"Rvalue is not an arithmetic type."); \
errlog(E_BAD_ARRAY_SIZE, N == _size); \
__VA_ARGS__ \
}
thus defining my function as
arithmetic_v(U, N,
void assign(U (&value)[N]),
idx_t i = 0;
do {
_address[i] = value[i];
} while (++i < _size);
)
This is somehow cleaner but still isn't the best since I'm forced to lose the brackets wrapping the function's body (having to include the static_assert INSIDE the function itself for the template parameter U to be in scope).
The question
The solution I've found seems to work pretty well and the code is much more readable than before, but... Can't I use another construct allowing me to build an even cleaner definition of all the functions and still preserving the static_assert piece and the info about the array size? It would be really ugly to repeat the template code once for each function I need...
The thanks
I'm just trying to learn about the language, thus ANY additional information about this argument will be really appreciated. I've searched as much as I could stand but couldn't find anything (maybe I just couldn't think of the appropriate keywords to ask Google in order to find something relevant). Thanks in advance for your help, and happy new year to you all!
Gianluca
I strongly suggest against using macros, unless there is no way around them (a case I could think of is getting the line number for debugging purposes). From the Google C++ Style Guide (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preprocessor_Macros):
Macros mean that the code you see is not the same as the code the compiler sees. This can introduce unexpected behavior, especially since macros have global scope.
I really don't see why you consider using a static_assert ugly. There is another way to ensure that a template is specialized only for some types using SFINAE.
template <class T, class Enable = void>
class X;
template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type> {
};
and you could do this even prettier using a using statement (no pun intended):
template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;
template <class T, class Enable = void>
class X;
template <class T>
class X<T, enable_if_integral_t<T>> {
};
And now
X<int> x; // ok, int is integral
X<float> y; // compile error
SFINAE (Substitution failure is not an error) is a feature in C++ in which you don't get an error if a template specialization fails.
template <bool Cond, class T = void> struct enable_if. The type T is enabled as member type enable_if::type if Cond is true. Otherwise, enable_if::type is not defined. So for a float type is_integral is false and enable_if::type doesn't exist, so the template specialization
template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type>
fails, but the generic template is used instead
template <class T, class Enable = void>
class X;
which is declared, but not defined.
This is useful as you can have more specializations like:
template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;
template <class T>
using enable_if_floating_t = typename std::enable_if<std::is_floating_point<T>::value>::type;
template <class T, class Enable = void>
class X;
template <class T>
class X<T, enable_if_integral_t<T>> {
};
template <class T>
class X<T, enable_if_floating_t<T>> {
};
Hope you find this at least interesting.
Happy new year!
Edit
Where should I put the <T, enable_if_integral_t<T>> in a function definition? I can only get this done with class templates...
For a function, the enable_if::type can be the return type. For example if f returns int, you can have:
#include <type_traits>
template <class T>
typename std::enable_if<std::is_integral<T>::value, int>::type f(T a) {
return 2 * a;
}
int main() {
f(3); // OK
f(3.4); // error
return 0;
}
and with using:
#include <type_traits>
template <class T, class Return = void>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value, Return>::type;
template <class T>
enable_if_integral_t<T, int> f(T a) {
return 2 * a;
}
int main() {
f(3); // OK
f(3.4); // Error
return 0;
}
I don't understand why you consider the static_assert or errlog statements so ugly, and suspect it's partly unfamiliarity with the language. Still, you could easily write a function or macro (if you want to use __LINE__ inside the assign etc. function), to move them out of line, allowing usage like:
template <class U, int N>
void assign(U (&s)[N]) {
assert_array_n_numbers(s);
idx_t i = 0;
do {
_address[i] = s[i];
} while (++i < size);
}
Can't I use another construct allowing me to build an even cleaner definition of all the functions and still preserving the static_assert piece and the info about the array size? It would be really ugly to repeat the template code once for each function I need...
In terms of what's possible - though IMHO likely undesirable obfuscation - you could have your functions accept (an) argument(s) that has a templated implicit constructor from an array, verifying it's arithmetic in that constructor then verifying size in the function using it, allowing usage like:
template <typename U>
void assign(Arithmetic_Array<U>& s) {
assert_same_size(s);
idx_t i = 0;
do {
_address[i] = s[i];
} while (++i < size);
}
Implementation:
template <typename T>
class Arithmetic_Array
{
public:
template <size_t N>
Arithmetic_Array(T (&a)[N])
: p_(&a), size_(N)
{
static_assert(std::is_arithmetic<T>(),"Rvalue is not an arithmetic type.");
}
T& operator[](size_t i) { return p_[i]; }
const T& operator[](size_t i) const { return p_[i]; }
size_t size() const { return size_; }
private:
T* p_;
size_t size_;
};
Discussion
"cleaner" can be subjective. In particular, you should consider the value of "normal" non-macro using-the-intuitive-type C++ source as documentation and for maintainability. If a macro substantially simplifies many functions - and particularly if it's only used in an implementation file and not a shared header - then it's worthwhile, but if there's only marginal benefit it's not worth the obfuscation and de-localisation. All that template stuff might seem convoluted and ugly when you're new to the language, but after a while it's understood at a glance and helps readers understand what the function goes on to do.
It's also common in C++ to embrace a "duck typing" attitude to template's parametric polymorphism. That means that you can let people pass in arguments of whatever type, and if those types support the operations that the template implementation attempts on them (i.e. compile), then hopefully it'll be what the caller wants. That's one reason that it's a good idea to create types that have predictable semantic behaviour, for example - only using operator overloading when the affect is similar to the same operators on built in types or std::string.
The stricter enforcement you'd like has its place though - Bjarne Stroustrup and others have spent a lot of time working on "Concepts" which are a mechanism for enforcing expectations on types used as template parameters, and would have been a good fit for your "arithmetic types" stipulation here. I hope they'll make it into the next C++ Standard. Meanwhile, static assertions are a good way to go.