The subject is already touched in this boost-variant-ambiguous-construction question.
But my issue is not with types convertible to each other, but with completely unrelated types.
Simplified example:
// types not related in any way
class A {};
class B {};
class C {};
class D {};
using ABC_variant = boost::variant<A,B,C>;
using D_optional = boost::optional<D>;
The issue was related with the fact that optional on some type was not printable. But, completely unrelated output operator for some variant was trying to accept this boost::optional type (D_optional).
See:
std::ostream& operator << (std::ostream& os, const ABC_variant&)
{
return os << "ABC";
}
int main() {
D_optional dopt;
std::cout << dopt;
}
You can see on ideone - plenty of compilers errors saying that it does not know what do you want to print bool or ABC_variant and in case of ABC_variant it does not know how to convert D_optional to ABC_variant. As I understand that boost::optional is convertible to bool and first alternative is correct I have no idea why it tries to use ABC_variant conversion...
Furthermore I simplified this example even more and give up with boost::optional:
int main() {
D d;
std::cout << d;
}
Now, it does not have "bool alternative" and just complaining that it tries to construct ABC_variant from D:
prog.cpp:23:15: required from here
/usr/include/boost/variant/variant.hpp:1591:38: error: no matching
function for call to 'boost::variant::initializer::initialize(void*, D&)'
initializer::initialize(
This here is ostream operator for ABC_variant.
Of course I know that writing ostream operator for D/D_opt will solve the issue - but the problem is with diagnostic: if boost::variant did not accept any type as argument for its constructor, the compiler would tell me simple true - not this bunch of misleading sentences...
I doubt it is in such way by design - maybe there is some fixes ongoing?
Fortunately I and ideone uses the same compiler and boost: gcc4.9 and boost1.58.
I have created boost ticket for this problem. Just to clarify what is the real problem:
Real problem is with this boost.variant "converting" constructor accepting any type - there is no restriction, even so natural like that argument type should be convertible to any of this boost.variant instantiation types:
template <typename T>
variant(const T& operand)
{
convert_construct(operand, 1L);
}
My proposed solution can be something like this:
template <typename T, typename ...C>
struct IsAnyOf;
template <typename T, typename ...C>
struct IsAnyOf<T,T,C...> : std::true_type {};
template <typename T>
struct IsAnyOf<T> : std::false_type {};
template <typename T, typename C1, typename ...C>
struct IsAnyOf<T,C1,C...> : IsAnyOf<T, C...> {};
template <typename T,
typename EnableIf = typename std::enable_if<IsAnyOf<VariantType...>::value>::type>
variant(const T& operand)
But for now - the only solution is not to create any non template function accepting instantiation of boost::variant. So either create function template or aggregate instantiation of boost::variant in some struct type.
So either this:
template <typename T>
typename std::enable_if<std::is_same<T,ABC_variant>::value, std::ostream&>::type
operator << (std::ostream& os, const T&)
{
return os << "ABC";
}
Or something like this:
struct ABC_variant
{
boost::variant<A,B,C> v;
ABC_variant(const A&);
ABC_variant(const B&);
ABC_variant(const C&);
};
The issue is fixed in boots.1.62
Related
I'm trying to use std::enable_if_t to enable a class if the template parameter is any type of std::string (bonus points for an answer that shows how to do this with a general string from multiple libraries).
I don't want to have to do "if Text is a const char*, std::string, std::string_view, etc." Essentially, I don't want to specifically mention every possible string-like object. All I'm going to do with this object is print it to console, and the Text object will be stored as a class attribute.
Is there a more elegant way of doing this than accounting for every individual type?
Checkout the type_traits library:
https://en.cppreference.com/w/cpp/header/type_traits
You are probably interested in is_constructible, is_convertible, or is_assignable depending on the exact method you want to use.
For example is_constructible<T, Args...> tests if there is a constructor T::T(Args...).
is_convertible<From, To> tests if To can be converted to From: e.g., following code compiles From Y = (From)X; where X is a To
You can use is_detected for this. We're trying to check whether the given type is printable with one of std::couts overloads of operator<< or if the type itself provides an operator<< for printing to std::cout. For a more general explanation of how I implemented this, check out https://www.fluentcpp.com/2017/06/02/write-template-metaprogramming-expressively/
First, we define an appropriate is_detected for the overloads of std::cout itself:
// check std::cout.operator<<(T {})
template<typename = void, typename Arg = void> struct test_operator_of_cout : std::false_type {};
template<typename Arg>
struct test_operator_of_cout<std::void_t<decltype(std::cout.operator<<(std::declval<Arg>()))>, Arg>
: std::true_type {};
template<typename Arg>
constexpr bool test_operator_of_cout_v = test_operator_of_cout<void, Arg>::value;
And another one for all overloads of operator<<(ostream&, T {}). The link I posted above generalizes this to have less code redundancy.
// check operator<<(std::cout, T {})
template<typename = void, typename Arg = void> struct test_operator_of_struct : std::false_type {};
template<typename Arg>
struct test_operator_of_struct<std::void_t<decltype(operator<<(std::cout, std::declval<Arg>()))>, Arg>
: std::true_type {};
template<typename Arg>
constexpr bool test_operator_of_struct_v = test_operator_of_struct<void, Arg>::value;
We can now use these type traits to implement the print function with enable_if:
template<typename T> struct MyClass {
T t;
template<
typename Consider = T,
typename = std::enable_if_t<
( test_operator_of_cout_v<Consider> || test_operator_of_struct_v<Consider>)
&& !std::is_arithmetic_v<Consider>
>
> void print() {
std::cout << t;
}
};
There are two things to note here:
You need the first template argument of Consider = T. Otherwise, the compiler will try to instantiate the declaration of the function, which is ill-formed for types that do not fullfil the condition. Check out this SO-Answer for a more in-depth explanation: std::enable_if to conditionally compile a member function
Arithmetic types are not printable because of the !std::is_arithmetic. I personally would not include this because I do not see a reason why my class shouldn't allow perfectly printable types to be printable.
Now we can look at what is printable and what not:
struct NotPrintable {};
struct Printable {
friend std::ostream& operator<<(std::ostream& os, const Printable& p) {
return os;
}
};
auto foo() {
MyClass<const char *> chars;
chars.print(); //compiles
MyClass<std::string> strings;
strings.print(); //compiles
MyClass<std::string_view> string_views;
string_views.print(); //compiles
MyClass<Printable> printables;
printables.print(); // compiles
// MyClass<int> ints;
// ints.print(); // Does not compile due to !is_arithmetiv_v
// MyClass<NotPrintable> not_printable;
// not_printable.print(); //Does not compile due to operator checking
}
You can check out the complete example here: https://godbolt.org/z/ZC9__e
I am trying to learn how to use SFINAE.
For practice purposes, I was trying to make an std::ostream wrapper in order to make a custom formatter.
Here is my SFINAE and custom output class.
// Tester
template <class O>
struct is_ostreamable {
template <class T>
static auto check(T t) -> decltype(std::declval<std::ostream &>() << t, std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
// Custom class
struct CustomOutput {
// Constructor etc...
CustomOutput(std::ostream &os = std::cout) : os{os} {}
std::ostream &os;
// Problematic template function
template <class O, class = std::enable_if_t<is_ostreamable<O>::value>>
CustomOutput &operator<<(O o) {
os << o;
return *this;
}
};
It words perfectly to not enable the template for struct or class that cannot be printed via operator<<.
However, with this SFINAE, ostream manipulators are not working... And I can't figure out why.
The error, and my expectations:
int main(void){
CustomOutput{} << "hi"; // Fine
std::vector<int> vec;
// CustomOutput{} << vec; // Error. Expected
CustomOutput{} << std::endl; // Error. WHY?
}
Maybe I missed something? Any help would be greatly appreciated.
First, fix your ostreamable class. Currently, your class requires T to be copy-constructible from 0. This is not the case for many classes. It should use std::declval to create the value instead:
template <class O>
struct is_ostreamable {
template <class T>
static auto check(int) -> decltype(std::declval<std::ostream &>() << std::declval<T>(), std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
Two changes are made here:
The operand to decltype uses std::declval<T>() to create the object of type T. std::declval<T> is an (intentionally undefined) function template that generates an object of type T when used in an unevaluated operand (such as that to decltype, or sizeof, noexcept operator, etc.) without dependence on a specific construction signature (copy-construction from 0 in your case).
The parameter to check is replaced with int. The initializer of the value variable calls check with the argument 0, so this int parameter ensures that (int) ranks higher than (...) in overload resolution, so that the true_type overload gets chosen when possible.
You need to provide a special overload for function-style manipulators (std::endl, std::flush, etc.):
using manip = std::ostream& (*)(std::ostream&);
CustomOutput& operator<<(manip m) {
os << m;
return *this;
}
There is, unfortunately, no way to make the generic template version support this feature. This is because std::endl is a function template:
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& endl(td::basic_ostream<CharT, Traits>& os);
For a function template to be used, the appropriate template arguments have to be determined. It is not possible to deduce the type-template parameter T as a generic template.
Anyway, this is probably the only special overload you are going to need.
I know there is already an accepted answer but I would like to mention a bit prettier C++20 way of doing the same thing by using concepts:
#include <iostream>
#include <concepts>
using OManipulator= std::ostream&(&)(std::ostream &);
template <typename T>
concept OStreamable = requires(T t) {
std::declval<std::ostream&>() << t;
};
struct CustomOutput {
std::ostream &os;
CustomOutput(std::ostream &os = std::cout)
: os{os}
{}
template <typename T> requires OStreamable<T>
CustomOutput& operator<<(T out) {
os << out;
return *this;
}
CustomOutput& operator<<(OManipulator out) {
os << out;
return *this;
}
};
int main(void){
CustomOutput{} << "hello";
CustomOutput{} << std::endl;
CustomOutput{} << "world";
}
Basically, in C++20, problem with manipulators needs to be solved in the same way as pre-C++20, by providing a special overload for them.
I have a class named has_f and I want it to only accept template parameters that have a f member function. How would I do that? This is what I tried:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
But I get some cryptic errors. Here is the class I want to use:
struct A
{
void f();
};
How do I do this correctly? Thanks.
From the title of your question I presume that you don't really need a type deriving from true_type or false_type - only to prevent compilation if method f is not present. If that is the case, and if you also require a specific signature (at least in terms of arguments) for that method, in C++11 you can do something like this:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
This is for the case when f() should not accept any arguments. std::add_pointer is only needed if f returns void, because sizeof(void) is illegal.
I +1ed rapptz yesterday for
"possible duplicate of
Check if a class has a member function of a given signature"
and haven't changed my mind.
I suppose it is arguable that this question unpacks to
"A) How to check if a class has a member function of a given signature and
B) How to insist that a class template argumement is a class
as per A)". To B) in this case I would answer with static_assert, since
the questioner apparently isn't interested in enable_if alternatives.
Here is a solution that adapts my answer to
"traits for testing whether func(args) is well-formed and has required return type"
This solution assumes that has_f<T>::value should be true if and only
if exactly the public member void T::f() exists, even if T overloads f or inherits f.
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(Built with clang 3.2, gcc 4.7.2/4.8.1)
This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream) on an object to serialize it. I realized I wanted this function call to one of four things:
If object is plain old data, just write out the size and raw data
If object is a class that I've created with its own member function (object::serialize), then call that member function
If there's a template specialization for that type, use it.
If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.
I have the following code:
#include <iostream>
#include <vector>
using namespace std;
struct A{};
struct B: public A {};
template <typename T>
void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
vector<int> v;
foo(v);
B b;
foo(b);
A a;
foo(a);
}
Output is
Generic case
Generic case
Specific case
Why is it that foo(const A& a) is not being chosen for the B object ?
Curiously enough, if I removed the templated method and just have the following:
#include <iostream>
#include <vector>
struct A{};
struct B: public A {};
//template <typename T>
//void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
B b;
foo(b);
A a;
foo(a);
}
The code compiles and the output is:
Specific case
Specific case
Why is the presence of the templated method making such a difference?
Edit: How can I force the compiler to choose the free method for classes derived from A in the presence
of the templated method?
No conversion is necessary for the call to foo(const B&) which the template instantiation yields thus it is the better match.
When a function call is seen by the compiler, every base function template has to be instantiated and is included in the overload set along with every normal function. After that overload resolution is performed. There is also SFINAE, which allows an instantiation of a function template to lead to an error (such a function would not be added to the overload set). Of course, things aren't really that simple, but it should give the general picture.
Regarding your edit: There is only one method to call. What else could there be as output?
Yes, it is a bit surprising but inheritance and template don't mix so well when it come to overload resolution.
The thing is, when evaluating which overload should be selected, the compiler chooses the one that necessitates the least conversions (built-in to built-in, derived-to-base, calls to non-explicit constructors or conversion operators, etc...). The ranking algorithm is actually pretty complex (not all conversions are treated the same...).
Once the overloads are ranked, if the two top-most are ranked the same and one is a template, then the template is discarded. However, if the template ranks higher than the non-template (less conversions, usually), then the template is selected.
In your case:
for std::vector<int> only one overload matches, so it is selected.
for A two overloads match, they rank equally, the template one is discarded.
for B two overloads match, the template rank higher (no derived-to-base conversion required), it is selected.
There are two work-arounds, the simplest is to "fix" the call site:
A const& ba = b;
foo(ba);
The other is to fix the template itself, however this is trickier...
You can hardcode that for classes derived from A this is not the overload you wish for:
template <typename T>
typename std::enable_if<not std::is_base_of<A, T>::value>::type
foo(T const& t) {
std::cerr << "Generic case\n";
}
However this is not so flexible...
Another solution is to define a hook. First we need some metaprogramming utility:
// Utility
template <typename T, typename Result = void>
struct enable: std::enable_if< std::is_same<T, std::true_type>::value > {};
template <typename T, typename Result = void>
struct disable: std::enable_if< not std::is_same<T, std::true_type>::value > {};
And then we define our hook and function:
std::false_type has_specific_foo(...);
template <typename T>
auto foo(T const& t) -> typename disable<decltype(has_specific_foo(t))>::type {
std::cerr << "Generic case\n";
}
And then for each base class we want a specific foo:
std::true_type has_specific_foo(A const&);
In action at ideone.
It is possible in C++03 too, but slightly more cumbersome. The idea is the same though, an ellipsis argument ... has the worst rank, so we can use overload selection on another function to drive the choice of the primary one.
#pmr's answer explains why the templated function is preferred in your example. To force the compiler to pick your overload instead, you can make use of SFINAE to drop the templated function from the overload set. Change the templated foo to
template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
foo(const T& obj) { cerr << "Generic case"<< endl;}
Now, if T is A or a class derived from A the templated function's return type is invalid and it will be excluded from overload resolution. enable_if is present in the type_traits header.
If I have
template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override
and a class
class A : public TalkySerialisable {
...}
Then if I perform
TalkyBuffer b;
A test;
b << test;
Then gcc is calling the Template function rather than the Override function
However if I specifically define an override
TalkyBuffer& operator<<(A const &object); // Override without polymorphism
Then gcc picks that one.
Is there a practical way to override a templated function with an abstract class?
I read this but it doesn't shed light onto what happens when you throw polymorphism into the mix:
http://www.gotw.ca/publications/mill17.htm
Also I couldn't find a solution here but perhaps I'm using the wrong terms.
When defining the function TalkyBuffer& operator<<(TalkySerialisable const &object); You are not overriding. You are overloading the tmeplated function.
But, when the complier sees b << test;, it searches for an operator that wants an A. It has one, it's the templated function that requires no automatic cast. This is the best choice.
The overloaded function requires an automatic cast (from A to TalkySerialisable) on the parameters to fit the declaration, and is not the best choice.
I think it's possible to use a simple function based solution, reusing function overload for derivation.
struct specialized {};
struct generic {};
template <class T>
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) {
...
}
generic dispatch(...) {} // always picked up last in overload resolution
template <class T>
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template
return serialize(*this, object, dispatch(object));
}
Now, let's implement your custom class:
TalkyBuffer& serialize(TalkyBuffer& buffer,
TalkySerialisable const& object,
specialized);
specialized dispatch(TalkySerialisable const&) {}
And create a derived one:
class A: public TalkySerialisable {};
So, what happens ?
TalkyBuffer::operator<<(T const&) will be picked up
when trying to resolve the overload for serialize, it will first compute the result of dispatch
when resolving the result of dispatch, dispatch(TalkySerializable const&) is a better match than dispath(...), thus the return type is specialized
the generic serialize cannot be used (there is no conversion from specialized to generic), so inheritance kicks in
A solution using Boost.enable_if:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
template<typename T>
typename boost::disable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object) { // Template for non TalkySerializable
...
}
template <typename T>
typename boost::enable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object); // Template overload for TalkySerializable
...
TalkyBuffer b;
A test;
b << test; // calls operator<< <A>(A const &), which instantiates
// the overload for TalkySerializable
b << 41; // calls operator<< <int>(int const &), which corresponds to
// the "default" overload
I'm not sure this is the best solution, but I failed to find a better one: specializing the template does not work either.
As #Matthieu noted in the comment, the previous solution has the major drawback that the base template needs to know that it will be overloaded, which is an unnecessary coupling that hinders extensibility.
To solve this problem, I came up with a new approach using tag dispatching, along with trait classes and compile-time introspection using Boost.MPL macros.
// TalkyBuffer.hpp
#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/has_xxx.hpp>
// defines a metafunction has_talky_buffer_tag<T> that allows us to know at
// compile-time if T has a member type named talky_buffer_tag
BOOST_MPL_HAS_XXX_TRAIT_DEF(talky_buffer_tag)
// tag for the default case
struct default_talky_buffer_tag {};
// trait class for obtaining the tag of a type
template <typename T, typename Enable = void >
struct talky_buffer_trait
{
typedef default_talky_buffer_tag type;
};
// specialization for types that provide a nested typedef
template <typename T>
struct talky_buffer_trait<T,
typename boost::enable_if<has_talky_buffer_tag<T> >::type>
{
typedef typename T::talky_buffer_tag type;
};
struct TalkyBuffer
{
// Insertion operator, which calls an implementation function that can
// be overloaded depending on the tag
template<typename T>
TalkyBuffer & operator<<(T const & object)
{
typename talky_buffer_trait<T>::type tag;
return insertionOperatorImpl(*this, object, tag);
}
};
// default implementation
template <typename T>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, T const & object,
default_talky_buffer_tag)
{
std::cout << "default";
return buf;
}
//-------
// TalkySerializable.hpp
struct TalkySerializable
{
struct tag {};
typedef tag talky_buffer_tag;
};
// A inherits from the nested typedef
struct A : public TalkySerializable {};
// implementation for TalkySerializable objects
template <typename Serializable>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, Serializable const & object,
TalkySerializable::tag)
{
std::cout << "specialized";
return buf;
}
//-------
int main()
{
TalkyBuffer b;
A test;
b << test; // outputs "specialized"
b << 41; // outputs "default"
}
To provide new implementations of the insertion operator for a given type T, one needs to provide a new type to act as a tag (TypeSerializable::tag in our example), provides a way to associate T with the new tag (either by using a nested typedef as in the example, or by specializing the trait class: template <> talky_buffer_trait<T> { typedef new_tag type };), and finally overload the implementation function (insertionOperatorImpl in the example).