Conversion is ambiguous in Visual Studio 2015, but not with clang - c++

The following code, a simplified version of code found in the googlemock project, fails to compile in Visual Studio 2015 Update 1, but it compiles on clang [Apple LLVM version 7.0.0 (clang-700.1.76)].
struct ConvertibleFromAny
{
ConvertibleFromAny(int a_value);
template <typename T>
ConvertibleFromAny(const T& a_value);
};
template <typename T>
struct Matcher
{
Matcher(T value);
};
template <typename Rhs>
struct EqMatcher
{
explicit EqMatcher(const Rhs& rhs);
template <typename Lhs>
operator Matcher<Lhs>() const;
};
int main()
{
EqMatcher<ConvertibleFromAny> em(1);
Matcher<ConvertibleFromAny> m = em;
return 0;
}
The error occurs at the assignment statement
Matcher<ConvertibleFromAny> m = em;
and the error message is
error C2440: 'initializing': cannot convert from 'EqMatcher<ConvertibleFromAny>' to 'Matcher<ConvertibleFromAny>'
note: No constructor could take the source type, or constructor overload resolution was ambiguous
I can naively see an ambiguity between a member call to
EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()
and an initialization conceptually similar to
Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))
My guess is that clang rules out the second option.
EDIT: Inspired by T.C.'s comment I tested the following:
struct A
{
};
struct X
{
X(const A&);
};
struct B
{
B(const X&);
};
int main()
{
A a;
B b = a;
}
It compiles with VS 2015, but not with clang. I have not been able to find any references that documents that the Visual C++ implementation intentionally deviates from the standard in this regard.
Is this a well-known problem?

Both your code samples produce the expected result with VS2015 Update 1, if I enable the "Disable Language Extensions" (/Za) flag. That is, the first one compiles, the second one does not.
I'm not sure which extension in particular is interfering here, though.
I found this MSDN page: Microsoft Extensions to C and C++, but it does not appear to be complete - for example, binding a non-const T& to an rvalue is not mentioned.

I have not been able to find any references that documents that the
Visual C++ implementation intentionally deviates from the standard in
this regard.
Here you go: Compiler Warning (level 1) C4928. The message is
illegal copy-initialization; more than one user-defined conversion has been implicitly applied
It also says this:
The compiler executed the code in all such routines.
So there's a de facto language extension that Microsoft has only barely documented.
You can use command line argument /we4928 to convert the warning into an error, effectively removing this single extension. See here for these arguments.

Related

Encounter the error: defaulted definition of default constructor is not constexpr when compile with clang-cl

I'm trying to compile these code with clang-cl with LLVM 15.
class Foo
{
public:
constexpr Foo() = default;
private:
int i;
};
int main(void)
{
Foo f;
}
The compilation command line is:
\> bazel build ... --compiler=clang-cl
The error will be displayed
cpp-constexpr/main.cpp(4,5): error: defaulted definition of default constructor is not constexpr
constexpr Foo() = default;
^
cpp-constexpr/main.cpp(13,9): error: no matching constructor for initialization of 'Foo'
Foo f;
^
cpp-constexpr/main.cpp(6,5): note: candidate constructor not viable: requires 1 argument, but 0 were provided
Foo(const Foo&) = delete;
^
2 errors generated.
Target //cpp-constexpr:constexpr failed to build
If it is compiled with MSVC 2022/2019, there will be no error at all. Looking forward to known your suggestions.
Thanks in advance.
TL;DR version: Compile to C++20 or a more recent version of the C++ Standard where both compilers should accept this code. Downside: you may find other discrepancies between their handling of C++20 and be no better off.
Explanation:
Quoting cppreference
for the constructor of a class or struct, every base class sub-object and every non-variant non-static data member must be initialized.
This is valid until C++20. As of C++20, the code should work as presented (but danged if I know what you'll do with a constant uninitialized variable i. Have to dig into the Standard or deeper into cppreference to see if i is zero initialized or something. This experiment with Matt Godbolt's compiler Explorer suggests it's not initialized.
So the fix is most likely to initialize i.
class Foo
{
public:
constexpr Foo() = default;
~Foo() = default;
Foo(const Foo&) = delete;
private:
int i = 0;
};
MSVC's ability to compile this code prior to C++20 appears to be a bug that could be fixed at any time. Rather than forcing incorrect behaviour onto clang-cl I recommend fixing the code (or compiling both sides to C++20 or more recent.

vs 2015 constexpr variable non constant but fine on vs 2019?

I have a simple constexpr class (using c++17)
struct foo {
float x, y;
// ill formed constexpr in vs 2015
foo() {}
constexpr foo(float x, float y) : x(x), y(y) {
}
};
constexpr auto bar() {
return foo(4.0, 5.0);
}
int main() {
auto f = bar();
}
This is illformed bc of the non constexpr default constructor on 2015. But vs 2019 doesnt report a problem.
According to this reference page "all selected ctors" must be constexpr. I assume the word "selected" means "used" and even though default ctor is unused, 2015 wont eval into a constexpr until I make the default ctor constexpr.
Other specs are worded differently but I could not make clear of them either. Also most constexpr examples use the keyword everywhere. An example of selective constexpr use would be nice.
Latest GNU ans Clang behave like vs 2019 but Im not convinced that this was an oversight or bug in vs 2015.
So what is it? Should all ctors be constexpr or is visual studio 2019 correct here?
There has never been a requirement that all constructors of a literal type must be constexpr. The requirement has only been that all functions which get invoked in a constant expression context must be able to be constant expressions (and thus must be declared constexpr).
Note that older versions of Visual Studio did not do a good job of implementing constexpr correctly.

Losing qualifiers during template argument deduction

Since I am using C++11, I have written my own make_unique function which takes a variadic template parameter pack and forwards it to the std::unique_ptr constructor. This works fine for simple data types. However, the objects I am trying to construct accept other type objects by const reference. On passing const references however, I am getting "Conversions loses qualifiers" i.e.
struct A {};
struct B { B(const A& ob) { ... } };
A ob;
auto ptr = make_unique<B>(ob); // error here
// Definition of make_unique below:
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>{ new T{std::forward<Args>(args)...} } ;
}
The error I am facing is
Conversions loses qualifiers, cannot convert argument 1 from 'const A' to 'A &'.
How do I resolve the error? From what I can understand, the template type deduction is not what I am expecting it to be.
Compiler: MSVC 2015, Update 3
This is most likely a compiler bug. It works fine with clang, g++, and also with current versions of MSVC 2017 as well as 2015. So I guess updating your Visual Studio should fix the issue.
working test example here
As it turns out, struct 'B' from the above code indeed changed it's constructor parameter to accept a non-const reference, but the documentation had no corresponding updates. Thank you everyone for the help!

C++11 vs C++98 conversion operator behavior changes?

I'm looking to use some c++11 features in some existing c++ projects, so I started changing compile flags in Clang for some projects, and I keep running into a specific issue regarding C++11's treatment of conversion operators (or cast operators) that I didn't expect to see and don't understand why this is now considered an error when it's been valid C++ code that's not c++11
I've boiled it down to this simple example:
#include <iostream>
#include <vector>
class SerializableFormat
{
public:
size_t i;
};
class A
{
public:
size_t x, y;
A(size_t n) : x(n), y(1) { }
operator const SerializableFormat() const
{
SerializableFormat result;
result.i = x;
if (y)
{
result.i /= y;
}
return result;
}
};
int main(int argc, const char * argv[])
{
std::vector<SerializableFormat> v;
for(size_t i = 0; i < 20; i++)
{
v.push_back(A(i));
}
return 0;
}
If Clang's compilation flags are set to -std=c++98 and libstdc++, there are no issues and this compiles fine.
If Clang's compilation flags are set to -std=c++11 and libc++, I get the error No viable conversion from 'A' to 'value_type' (aka 'SerializableFormat')
Just to make it clear-- in case you're thinking about giving SerializableFormat a constructor just for the class A:
Since the SerializableFormat class is more suited for conversion to and from various classes, it makes sense for A (and other classes that wish to be serializable) to have constructors and conversion operators rather than expect SerializableFormat to cover every type of class that wants to be serializable, so modifying SerializableFormat to have a special constructor is not a solution.
Can anyone see what I'm doing wrong here?
As the comments correctly note, you can get compiling by dropping the const in the return type of your SerializableFormat conversion operator:
operator const SerializableFormat() const
As to whether clang is correct in this behavior is a matter of some dispute. The issue is being tracked by clang bug report 16682. At this time there is talk of creating a CWG (C++ committee) issue report, but that has not yet been done. I note that this bug report has been open for some time now (2013-07-23), but was updated as recently as 2015-01-28.
In the meantime, practical advice is just never to return by const-value. This was decent advice for C++98/03, but with move semantics becomes bad advice because it will disable move semantics.

Inconsistent brace-or-equal initialization behavior between MSVC and Clang

I have the following code which I compile on Visual Studio 2013 and Clang:
#include <memory>
template<typename T>
class foo
{
public:
typedef void (T::*CallbackFn)();
foo(T* mem, CallbackFn cb) : m_member(mem), m_cb(cb) {}
private:
T* m_member;
CallbackFn m_cb;
};
class another
{
private:
void callback() {}
public:
std::unique_ptr<foo<another>> f{new foo<another>(this, &another::callback)};
};
int main() {}
(Live sample here on Coliru)
When compiled on clang and GCC, this code works fine. However on VS2013 it fails with:
main.cpp(22): error C2276: '&' : illegal operation on bound member function expression
main.cpp(22): error C2664: 'foo<another>::foo(const foo<another> &)' : cannot convert argument 1 from 'another *const ' to 'const foo<another> &'
Reason: cannot convert from 'another *const ' to 'const foo<another>'
No constructor could take the source type, or constructor overload resolution was ambiguous
For some reason, VS compiler is trying to invoke the copy constructor of foo, which makes no sense at all. It's ignoring the 2nd parameter to the constructor entirely.
Interestingly if I change the constructor invocation of foo to braces like so:
std::unique_ptr<foo<another>> f{new foo<another>{this, &another::callback}};
It works just fine on MSVC. Can anyone explain this behavior? Is one way more correct than the other? Is this just another MSVC bug or due to some unsupported C++11 feature?
Can anyone explain this behavior?
Once the compiler encounters the first error, the rest is just junk. Ignore it. (I generally only look at the first compiler error that comes up, see here for VC++)
Is one way more correct than the other?
Both are completely equivalent in this context. MSVC simply fails to parse &another::callback and subsequently ignores it for further analysis of the line.