My issue is best demonstrated by the following code:
#include <fstream>
#include <iterator>
class Bar
{
public: template <class Iterator> Bar(Iterator first, Iterator last) {}
};
void foo(const Bar& bar) { }
int main(int argc, char** argv)
{
std::ifstream file("file.txt");
Bar bar(std::istream_iterator<char>(file), std::istream_iterator<char>());
foo(bar); // error C2664: 'foo' : cannot convert parameter 1 from 'Bar (__cdecl *)(std::istream_iterator<_Ty>,std::istream_iterator<_Ty> (__cdecl *)(void))' to 'const Bar &'
// with
// [
// _Ty=char
// ]
// Reason: cannot convert from 'overloaded-function' to 'const Bar'
// No constructor could take the source type, or constructor overload resolution was ambiguous
return 0;
};
Here are some similar instantiations of bar that don't cause the same ambiguity:
Bar bar = Bar(std::istream_iterator<char>(file), std::istream_iterator<char>());
and
std::istream_iterator<char> start(file);
std::istream_iterator<char> end;
Bar bar(start, end);
My question is, what is it about the first declaration of bar that causes it to be misinterpreted?
note: I'm testing with Visual Studio 2010 (10.0.30319.1)
ArunMu gets partial credit, it is indeed an example of Most Vexing Parse, but that term was coined in Meyer's Effective STL (Chapter 1, Item 6) not Exceptional C++.
It is being interpreted as a function pointer (the (__cdecl *) portion of the error is a dead give away), and apparently the C++ standard requires it to be interpreted that way. Does anyone have a chapter/verse citation for that?
There is also a another solution to provide a disambiguation. Adding an additional set of parenthesis around each parameter works too:
Bar bar( (std::istream_iterator<char>(file)), (std::istream_iterator<char>()) );
It's also worth pointing out that the issue is unrelated to the templates, as I had originally thought.
I think it is related to "C++ most vexing parse" that you will find in Meyer's Effective STL book.
Bar bar(std::istream_iterator< char >(file), std::istream_iterator < char >());
Is being considered as a **function declaration.**
due to which in foo(bar); you are sending a function pointer instead :)
Doing like below will have no error:
Bar bar = Bar(//your arguments here);
foo(bar);
Related
I upgraded to the latest release of Google Test, and several of my tests no longer compiled. I've reduced it to this:
#include <gtest/gtest.h>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
int main () {
const std::string foo = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const auto uppers = std::count_if(foo.begin(), foo.end(), std::isupper);
std::cout << "There are " << uppers << " capitals." << std::endl;
return 0;
}
The Visual Studio 2019 (16.10.4) compiler with /std:c++latest complains:
1>Source.cpp(10,30): error C2672: 'std::count_if': no matching overloaded function found
1>Source.cpp(10,75): error C2780: 'conditional_t<std::_Is_from_primary<std::iterator_traits<remove_cv<remove_reference<_Ty2>::type>::type>>,std::incrementable_traits<remove_cv<remove_reference<_Ty2>::type>::type>,std::iterator_traits<remove_cv<remove_reference<_Ty2>::type>::type>>::difference_type std::count_if(_ExPo &&,const _FwdIt,const _FwdIt,_Pr) noexcept': expects 4 arguments - 3 provided
1>algorithm(570): message : see declaration of 'std::count_if'
1>Source.cpp(10,30): error C2783: 'conditional_t<std::_Is_from_primary<std::iterator_traits<remove_cv<remove_reference<_Ty>::type>::type>>,std::incrementable_traits<remove_cv<remove_reference<_Ty>::type>::type>,std::iterator_traits<remove_cv<remove_reference<_Ty>::type>::type>>::difference_type std::count_if(_InIt,_InIt,_Pr)': could not deduce template argument for '_Pr'
1>algorithm(553): message : see declaration of 'std::count_if'
If I comment out the inclusion of gtest.h, the code builds and executes correctly.
What could gtest.h be doing that messes up template argument deduction for a call that depends only on std-defined types and functions?
[Note, my question is not how to workaround the problem, but to understand the specific underlying cause. I have a workaround: Replace the std::isupper with a lambda.]
It appears that <gtest/gtest.h> is now including <locale>, which introduces
template< class charT > bool isupper( charT ch, const locale& loc )
into the scope. That means that std::isupper now has two possible functions it could point to and without you specifying which one to use, you get an ambiguity which causes template argument deduction to fail.
If you do go the lambda route to fix this, make sure you cast the input to std::isupper to an unsigned char like
const auto uppers = std::count_if(foo.begin(),
foo.end(),
[]()(auto ch){ return std::isupper(static_cast<unsigned char>(ch));} )
Using the MS command line C++ compiler, version as indicated in the output below, compiling the following fails with the compiler report as included:
// File: shared_memory.h
template <class Contents>
class SharedMemory {
public:
...
operator Contents& () {
...
}
...
SharedMemory &operator= (Contents &contents) { // [EDIT] CONST REMOVED AT PARAMETER
...
}
...
};
// File: shared_memory_test.cpp
class SharedAnimals: public SharedMemory <Animals> {
...
using SharedMemory <Animals>::operator=; // [EDIT] HAD TO BE ADDED
...
}; // This is line 67 in the original code
int main (int argc, char** argv) {
...
Animals animals (kind);
...
sharedAnimals = animals; // This is line 93 in the original code
...
}
// Compiler reports:
shared_memory_test.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\include\xlocale(319): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
shared_memory_test.cpp(93): error C2679: binary '=': no operator found which takes a right-hand operand of type 'Animals' (or there is no acceptable conversion)
shared_memory_test.cpp(67): note: could be 'SharedAnimals &SharedAnimals::operator =(SharedAnimals &&)'
shared_memory_test.cpp(67): note: or 'SharedAnimals &SharedAnimals::operator =(const SharedAnimals &)'
shared_memory_test.cpp(93): note: while trying to match the argument list '(SharedAnimals, Animals)'
Can anyone give me a hint on what I am doing wrong?
[EDIT]
Indeed the answer at Assignment operator inheritance provided by user1810087 solved the problem.
While the answer is already there, the context of this question, namely using a template class, led me to believe that the error was connected to that, and did not look for questions relating to "assignment operator inheritance".
Since I may not be the only one running into this, I suggest this question be maintained.
I have simple code.
template<typename T>
class NamedObject{
public:
NamedObject(std::string& name, const T& value):nameValue(name), objectValue(value)
{
}
private:
std::string& nameValue;
const T objectValue;
};
int main(int argc, char* argv[])
{
NamedObject<int> no1("Smallest Prime Number",2);//error
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);//works
return 0;
}
When I make first parameter as non refrence, both no1 and no2 object gets created. But when I keep reference Visual Studio compiler gives following error,
Error 1 error C2664: 'NamedObject::NamedObject(std::string &,const
T &)' : cannot convert parameter 1 from 'const char [22]' to
'std::string &' c:\users\pkothari\documents\visual studio
2008\projects\stackoflw\stackoflw\stackoflw.cpp 36
If char * can be casted to std::string, why not to std::string& ? Is there any way to make it work?
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);//works
That should not work in a standard compliant compiler. It is supported in MS Visual Studio C++ even though it is not standard C++.
Neither of the following calls should work when the expected argument is std::string&.
NamedObject<int> no1("Smallest Prime Number",2);
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);
Both of them should work when the argument type is std::string or std::string const&.
I have the following code:
typedef bool (A::*rule)(shared_ptr<Node >, shared_ptr<Node> ) ;
when initilaising the class A object, I run the following code
v_ = vector<rule>();
v_.push_back(A::memberFunction);
I have also tried with v_.push_back(&A::memberFunction) as this seemed more logical to me, but was
advised against on the forums. I also get an error message
This is as suggested by the many topics on the matter. However, I get the following error
non-const lvalue reference to type 'value_type' (aka 'bool (boost::shared_ptr<Node>, boost::shared_ptr<Node>)')
cannot bind to a temporary of type '<bound member function type>'
Does anyone know where I am going wrong?
I have also tried with v_.push_back(&A::memberFunction) as this seemed more logical to me, but was advised against on the forums.
I don't know what forums were those. Forming a pointer-to-member has a single valid syntax, and it is & classname::membername. All elements mandatory.
Use that consistently and post code and error message for that version should the problem persist.
This code compiles under llvm/clang 4.2 (As #balog-pal said, the & is mandatory before classname::membername:
#include <memory>
#include <vector>
struct Node {};
struct A
{
bool rule(std::shared_ptr<Node>, std::shared_ptr<Node>)
{return true;}
};
typedef bool (A::*rule)(std::shared_ptr<Node>, std::shared_ptr<Node> );
int main(int, const char**)
{
std::vector<rule> v;
v.push_back(&A::rule);
return 0;
}
Please post a full not-compiling example, your issue must be hidden somewhere else.
I have to implement a function that takes an iterator. The iterator must dereference to a certain type, say int:
template<typename iter>
void f(iter i) {
// do something here ...
int t = *i;
// do something here ...
}
The problem with this code is that if a user calls the function like this
vector<string> v;
v.push_back("aaa");
f(v.begin());
he will see an error pointing to some place in my code, not in his code (which will be confusing to him). I want the error to be in user's code to ease debugging.
GMan already pointed to a method to solve this via compile time assertions. There is another way to do this, which I prefer (it's my favorite C++ technique). You can put constraints on function arguments in a way that the function is ignored for overload resolution if the constraints don't fit. This is quite terrific, because you can fine tune your function overloads to arbitrary conditions. Here's how:
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <vector>
template<typename Iter> typename
boost::enable_if<
boost::is_same<typename Iter::value_type,int>,
void>::type
foo(Iter it) { }
int main() {
std::vector<int> v; // this is OK
foo(v.begin());
std::vector<double> v2; // this is an error
foo(v2.begin()); }
If you compile this, you will get
b.cc: In function 'int main()':
b.cc:19:16: error: no matching function for call to 'foo(std::vector<double>::iterator)'
This is because the compiler would consider foo() only, if it's argument has a value_type type inside, which is 'int' (This is what the enable_if part means). The second call of foo() can't satisfy this constraint.
enable_if is mentioned a couple of times in SO, just search for it: https://stackoverflow.com/search?q=enable_if
You could do something like this:
#include <boost/type_traits/is_convertible.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/mpl/assert.hpp>
template <typename Iter>
void foo(Iter pIter)
{
BOOST_MPL_ASSERT_MSG(
(boost::is_convertible<BOOST_TYPEOF(*pIter), int>::value),
DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT,
(int));
// ...
}
#include <vector>
#include <string>
int main(void)
{
std::vector<std::string> v(5);
foo(v.begin());
}
Which makes the message quite visible:
error C2664: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from 'boost::mpl::failed ************(__thiscall foo::DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT::* ***********)(int)' to 'boost::mpl::assert::type'
But like James says, most compilers give plenty of information to find out what happened anyway.
Given the code in question, most compilers will refer to the point of instantiation in the diagnostic message. For the following, line 16 is the line f(v.begin());.
Microsoft Visual C++ reports:
> c:\example\main.cpp(16) : see reference to function template instantiation 'void f<std::_Vector_iterator<_Myvec>>(iter)' being compiled
1> with
1> [
1> _Myvec=std::_Vector_val<std::string,std::allocator<std::string>>,
1> iter=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>
1> ]
g++ reports:
main.cpp:16: instantiated from here
Intel C++ Compiler and Comeau both report:
detected during instantiation of
"void f(iter) [with iter=std::string *]" at line 16
You need to set a constraint on the generic type.