How does this code not compile? Why can bs[1] not be deduced to bool?
Is there a generic way to solve this problem?
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
template<typename T> struct StringConverter{};
template<> struct StringConverter<bool>{
std::string operator()(const bool &i){ return i?"true":"false"; }
};
template<typename T> std::string to_string(const T &val){
return StringConverter<T>()(val);
}
int main(){
// this does not compile
std::bitset<10> bs;
std::cout << to_string(bs[0]) << std::endl;
// this does
const std::bitset<10> bs_const;
std::cout << to_string(bs_const[0]) << std::endl;
}
Compiler Error:
main.cpp:12:12: error: type 'StringConverter<std::bitset<10>::reference>' does not provide a call operator
return StringConverter<T>()(val);
^~~~~~~~~~~~~~~~~~~~
main.cpp:18:18: note: in instantiation of function template specialization 'to_string<std::bitset<10>::reference>' requested here
std::cout << to_string(bs[0]) << std::endl;
^
1 error generated.
the non-const bitset::operator[] returns a proxy object rather than a bool (this has to be done because that proxy can be used to change the bit value). const bitset::operator[] however just returns a bool (not a reference, just a plain bool) so it matches for the StringConverter[
If you check the declaration of operator[], you'll notice it has two overloads - the const one, which returns bool and is used in your second example, and the non-const, which returns the object of type std::bitset::reference.
The latter is used for bit field modification, and it absolutely cannot be a bool& since it has to address a specific bit. The problem you ran into is quite common for these proxy return types (this is where I should mention vector<bool>).
As a possible solution you can use the fact that std::bitset::reference is convertible to bool (and is not convertible to any other conceivable type that you might use for your StringConverter specializations).
Related
I wrote a simple SFINAE-based trait to detect whether a class has a method with a specific signature (the back story is that I am trying to detect whether a container T has a method T::find(const Arg&) - and if yes, then store a pointer to this method).
After some testing I discovered a case where this trait would give a false positive result - if T defines the method as a template but definition compiles not for all possible Ts. This is best demonstrated with an example:
#include <iostream>
#include <string>
#include <vector>
#include <type_traits>
using namespace std;
// HasFooWithArgument is a type trait that returns whether T::foo(const Arg&) exists.
template <typename T, typename Arg, typename = void>
inline constexpr bool HasFooWithArgument = false;
template <typename T, typename Arg>
inline constexpr bool HasFooWithArgument<T, Arg, std::void_t<decltype(std::declval<const T&>().foo(std::declval<const Arg&>()))>> = true;
// Below are the test cases. struct E is of the most interest.
struct A {};
struct B {
void foo(int x) const {}
};
struct C {
void foo(int x) const {}
void foo(const std::string& x) const {}
};
struct D {
template <typename T>
void foo(const T& x) const {}
};
struct E {
// Any T can be substituted (hence SFINAE "detects" the method)
// However, the method compiles only with T=int!
// So effectively, there is only E::foo(const int&) and no other foo methods...
template <typename T>
void foo(const T& x) const {
static_assert(std::is_same_v<T, int>, "Only ints are supported");
}
};
int main()
{
cout << std::boolalpha;
cout<<"A::foo(int): " << HasFooWithArgument<A, int> << "\n";
cout<<"B::foo(int): " << HasFooWithArgument<B, int> << "\n";
cout<<"C::foo(int): " << HasFooWithArgument<C, int> << "\n";
cout<<"C::foo(string): " << HasFooWithArgument<C, std::string> << "\n";
cout<<"C::foo(std::vector<int>): " << HasFooWithArgument<C, std::vector<int>> << "\n";
cout<<"D::foo(string): " << HasFooWithArgument<D, std::string> << "\n";
cout<<"E::foo(int): " << HasFooWithArgument<E, int> << "\n";
cout<<"E::foo(string): " << HasFooWithArgument<E, std::string> << "\n";
E e;
e.foo(1); // compiles
// e.foo(std::string()); // does not compile
return 0;
}
The above prints:
A::foo(int): false
B::foo(int): true
C::foo(int): true
C::foo(string): true
C::foo(std::vector<int>): false
D::foo(string): true
E::foo(int): true
E::foo(string): true
Unfortunately, this last case is my main target: as I mentioned above, I am doing this to detect container find methods and they are usually defined as templates to support heterogeneous lookup.
In other words, std::set<std::string, std::less<>> is where my detection gives false positives as it returns true for any argument type.
Thanks in advance!
The issue you're describing is not due to the fact that SFINAE doesn't work properly with function templates (it does). It has to do with the fact that SFINAE can't detect whether a function body is well-formed.
Your approach should work just fine when it comes to detecting that std::set<std::string> does not have a find member that takes a std::string_view argument. This is because the templated find member does not participate in overload resolution unless the set has a transparent comparator. Since std::set<std::string> doesn't have a transparent comparator, its find function will only accept types that are implicitly convertible to std::string; any attempt to pass any other type will result in an overload resolution failure, which will be detected by SFINAE just like any other case of an argument type mismatch.
Where your approach won't work is with something like std::set<std::string, std::less<>> and trying to call find with an argument type of say, int. In this case the detection will succeed because the find template is unconstrained, but then compilation will fail later on if you try to actually call find with an int argument, because somewhere in the body, it will try to call std::less<> with types that can't be compared with each other (std::string and int).
Colloquially, we say that a function or a class that makes it possible to detect using SFINAE whether it, itself, would be well-formed, is "SFINAE-friendly". In that sense, std::set::find fails to be SFINAE-friendly. To make it SFINAE-friendly, it would have to guarantee that an overload resolution failure would occur if you tried to call it with a type that isn't comparable using the specified transparent comparator.
When something is not SFINAE-friendly, the only workaround is to special-case it: in other words, you have to put in your code a special case that makes detection fail for std::set::find in this case, by checking explicitly whether the comparator accepts the argument type. (std::less<> is SFINAE-friendly: it does the overload resolution in the (explicitly specified) return type.)
I want to define a template function that gets one argument passed by value for all types but std::string (and const char*).
template<typename T>
void foo( T value )
{
// some code using value
}
The std::string version should behave exactly as the template version, but have its parameter passed by const&.
What is the best approach to do what I want without duplicating the body of foo()?
The best I was able to think is to wrap the code using value inside another function, and then call it inside all versions of foo() (the template version and the std::string overload). Is there another way? For example, is it possible to call the template version from within the std::string overload?
EDIT
What I want to know is a good rule of thumb for avoiding code duplication among various specializations and overloads. What is a good pattern to follow? Shall I define a wrapper function for the body and then call that from within all overloads/specializations, or there is another way?
In order to avoid code duplication, the answer by 101010 can be extended to actually call the template from within the overload:
#include <string>
#include <iostream>
#include <type_traits>
#include <boost/core/demangle.hpp>
template<typename T>
void foo( T value )
{
std::cout << "inside template" << std::endl;
std::cout << boost::core::demangle(typeid(value).name()) << std::endl;
}
void foo(const std::string &value)
{
std::cout << "inside const string overload" << std::endl;
foo<const std::string&>(value);
}
int main()
{
foo(10);
foo(std::string("hello"));
return 0;
}
output
inside template
int
inside const string overload
inside template
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
live example
Simple solution: provide an overload for std::string:
void foo( std::string const &value ) {
// some code using value
}
I think what you are looking for is rvalue signature in C++ 11.
Its as simple as:
#include <iostream>
#include <string>
template<typename T>
void foo(T&& value)
{
std::cout << "was passed by refernece:" << std::is_lvalue_reference<T&&>::value << std::endl;
std::cout << value << std::endl;
}
int main()
{
std::string text = "hello";
foo(text);
foo(1);
}
You can either pass the parameter by reference or by value and the rvalue rules will use the appropriate type.
You can define a type-trait-like class that will convert std::string to std::string& and will keep the type for all other types:
template<class T>
struct helper {
typedef T type;
};
template<>
struct helper<std::string> {
typedef std::string& type; // or const std::string& type if you want
};
template<typename T>
void foo( typename helper<T>::type value, T value2 )
{
value = value2;
}
int main()
{
int a = 10;
foo(a, 42);
std::cout << a << std::endl; // prints 10
std::string s = "abc";
foo(s, std::string("def"));
std::cout << s << std::endl; // prints def
}
Full example: http://coliru.stacked-crooked.com/a/96cf78e6c4846172
UPD: as noted by #PiotrSkotnicki, having only one parameter makes type-deduction fail. However, I will keep the answer as it might be helpful in case you indeed have several parameters of type T or if you are ok with specifying explicit template parameter to foo.
UPD2: To solve the type-deduction problem, you may add another wrapper:
template<typename T>
void foo_helper( typename helper<T>::type value )
{
value = T();
}
template<typename T>
void foo(T& value)
{
foo_helper<T>(value);
}
This still might have some problems, so whether this is applicable to your usecase, is up to you to decide.
use std::enable_if + std::is_convertibale:
template<typename T>
typename std::enable_if<!std::is_convertible<T,std::string>::value>::type foo( T value )
{
// some code using value
}
I am providing a library that supports a function bar(). What it does when you pass in a scalar value (like a double, int, whatever) is different from what happens if you pass in something that is not a scalar value (in all expected cases, a user-defined type). So I wrote code like this:
#include <iostream>
class Foo
{
public:
template <class T> void bar(T const &rhs) { std::cout << "T" << std::endl; }
void bar(double rhs) { std::cout << "double" << std::endl; }
};
int main()
{
Foo foo;
foo.bar(4);
}
The problem with this is on the second line of main(). The result of this code is output of "T". The compiler prefers the template over the call to bar(double), and I am assuming this is because the parameter is an int, which it would rather cast to int const& (since a const& can reference an r-value).
My question is "is there a way I can support every scalar value without explicitly calling them out?" I really don't want to call out every possible type, because... well... there's a lot of them. I would have to cover everything from char to long long, include every combination of volatile and unsigned, and so forth.
I know that just changing the 4 to a 4.0 works, but this is for the public interface to a library, and requiring the user to type 4.0 instead of 4 is just dirty.
Yes, with traits:
#include <type_traits>
#include <iostream>
class Foo
{
public:
template <class T>
typename std::enable_if<!std::is_scalar<T>::value, void>::type bar(T const & rhs)
{
std::cout << "T" << std::endl;
}
void bar(double rhs)
{
std::cout << "double" << std::endl;
}
};
There are six basic categories of types: scalars, functions, arrays, classes, unions and references. And void. Each of them have a corresponding trait. See here for more details.
I have some code.
#include <iostream>
template<typename T>
struct Test
{
Test(bool v):flg(v) { }
void func() { }
typedef void (Test::*unspecified)();
operator unspecified() const
{
return flg ? &Test::func : 0;
}
bool flg;
};
template<typename T>
std::ostream& operator << (std::ostream&, typename Test<T>::unspecified);
int main()
{
Test<int> t(true);
std::cout << t << std::endl;
}
Output is
1
It works fine, but i want to get undefined reference. If Test is not template class i get undefined reference. So, why compiler not use operator << for function type and do standart conversion from pointer to class-member to bool?
In typename Test<T>::unspecified, T is in a non-deducible context, since it appears to the left of a ::. Thus your function template is never even considered, and the conversion to unspecified is used as the sole viable overload.
The short answer is simply that "templates don't work like that". Let me know if you want a longer answer.
I'm using a test framework (tut) and noticed a lot of repeatability so I started to abstract out the predicate functions i needed. Below is a simplified example.
It works but I was hoping I could all do it in one line. The problem is when i try to instantiate the derived predicate class inline it fails to compile. Any ideas why?
#include <string>
#include <functional>
#include <iostream>
using namespace std;
template <class T>
struct TestPredicate : public binary_function<T,T,bool>
{
virtual bool operator() (const T& expected, const T& data) const = 0;
};
template <class T>
struct IsEqual : public TestPredicate<T>
{
virtual bool operator() (const T& expected, const T& data) const
{
cout << "IsEqual: " << expected << ", " << data << endl;
return data == expected;
}
};
template <class T>
struct IsNotEqual : public TestPredicate<T>
{
virtual bool operator() (const T& expected, const T& data) const
{
cout << "IsNotEqual: " << expected << ", " << data << endl;
return data != expected;
}
};
struct Tester
{
template <class T>
void test( const T& data, const T& expected, TestPredicate<T>& value_condition )
{
if ( value_condition( expected, data ) )
{
cout << "PASSED" << endl;
}
else
{
cout << "FAILED" << endl;
}
}
};
int main()
{
Tester test;
string data("hello");
string expected("hello");
// this doesn't compile with an inline instantiation of IsEqual
//test.test( data, expected, IsEqual<string>() ); // compilation error (see below)
// this works with an explicit instantiation of IsEqual
IsEqual<string> pred;
test.test( data, expected, pred );
return 0;
}
Compilation Output:
test2.cpp: In function ‘int main()’:
test2.cpp:61:48: error: no matching function for call to ‘Tester::test(std::string&, std::string&, IsEqual<std::basic_string<char> >)’
test2.cpp:61:48: note: candidate is:
test2.cpp:40:8: note: void Tester::test(const T&, const T&, TestPredicate<T>&) [with T = std::basic_string<char>]
test2.cpp:40:8: note: no known conversion for argument 3 from ‘IsEqual<std::basic_string<char> >’ to ‘TestPredicate<std::basic_string<char> >&’
Using g++ 4.6.3
In addition to the other answers, you don't really need runtime polymorphism with virtual functions. You could just make the tester take another template parameter:
template<class T, class Pred>
void test( const T& data, const T& expected, Pred value_condition )
Your Tester::test method needs to take a const reference to the predicate to work with both instantiations.
Temporary object are always const, that is way in test.test( data, expected, IsEqual<string>() ); IsEqual<string>() is of type const TestPredicate<T>.
The explanation to why the compiler complains is both simple and... a bit disheartening.
The C++ Standard rules out that a temporary object (such as created by the expression IsEqual<string>()) can be bound to a const reference, in which case its lifetime is extended to that of the reference.
Because Stroustrup feared that binding to non-const references would only be a source of bugs, it is not however allowed. With hindsight, it turns out that the absence of symmetry is often more surprising; VC++ allows binding to non-const references (as an extension). In C++11, the balance is somewhat restored by allowing binding to "reference reference" (&&), though it still leaves a gap...
... and leaves us in the unpleasant situation you find yourself in.
On the web this is may be referred to as the Most important const.