Microsoft Visual Studio Professional 2015 Version 14.0.25431.01 Update 3
does not issue errors when compiling the code below. Am I missing something?
Thank you.
#include <iostream>
template < class T > constexpr T oops( T s )
{
std::cout << s; // ignored - no code is generated
return s;
}
int main()
{
static_assert( oops( 1 ) == 1, "!" ); // non-constant condition not detected
return 0;
}
Related
Scenario
I have a C++ function which intakes a parameter as std::chrono::milliseconds. It is basically a timeout value. And, it is a default parameter set to some value by default.
Code
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someTimeout = std::chrono::milliseconds(100)) {
if (someTimeout > 0) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count() << std::endl;
}
}
int main() {
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue))
}
Issue
All of above is okay but, when I call Fun with a value then fails to compile and I get the following error:
No viable conversion from 'bool' to 'std::chrono::milliseconds' (aka
'duration >')
Question:
What am I doing wrong here? I want the caller of Fun to be explicitly aware that it is using std::chrono::milliseconds when it invokes Fun. But the compiler doesn't seem to allow using std::chrono::milliseconds as a parameter?
How use std::chrono::milliseconds as a default parameter?
Environment
Compiler used is clang on macOS High Sierra
With the other syntax errors fixed, this compiles without warnings in GCC 9:
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someNumberInMillis
= std::chrono::milliseconds(100))
{
if (someNumberInMillis > std::chrono::milliseconds{0}) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count()
<< std::endl;
}
}
int main()
{
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue));
}
One of the answers in SO states that we cannot bind a non const l-value reference to an r-value. This is a sample code.
#include <iostream>
using namespace std;
struct Position2D
{
float m_x;
float m_y;
Position2D(float x, float y) : m_x(x), m_y(y)
{
}
};
int main()
{
Position2D& p2 = Position2D(2, 2); // this is the line which has the problem.
Position2D&& p3 = Position2D(2, 2);
return 0;
}
The problem is Visual Studio 2013 compiler compiles above mentioned code segment without any error. But online c++11 compiler shows an error as the link which included in SO answer describes. Who is correct? Is there any problem in Visual Studio 2013 C++ compiler with new C++11 standards?
Code with statements such as those shown below compiles fine with g++.exe (x86_64-posix-seh-rev4, Built by MinGW-W64 project) 4.8.2, but not with the latest Visual Studio 2013 Update 3 CTP 2 (12.0.306020.00 Update 3 CTP)
Questions: Might I be doing something wrong such as not turning on some feature or does the latest Visual Studio 2013 not support such statements? The code needs to be made to compile under Visual Studio -- any suggestions on how to work around this limitation?
namespace NA
{
namespace NB
{
class C1 : P1
{
static constexpr double one = 1.0;
static constexpr double two = one + one;
static constexpr float a_foo[][2] = { { 1.0, 1.1, 1.2 },
{ 2.0, 2.1, 2.2 } };
static constexpr int n_ele = 1024;
static constexpr int n_d = 128;
static constexpr int n_ape = n_ele -
n_d +
1;
std::vector< std::array< int, (int)n_ele >> ape
{
std::vector< std::array< int, (int)n_ele >>
( (int)n_ape, {{0}} )
};
std::array<
std::array< int, (int)n_d >,
(int)n_ape
> c_to_e = {{ std::array< int, (int)n_d >( {0} ) }};
}
}
}
According to this blog, C++11 constexpr is listed as Partial because VS doesn't support it on member functions.
C++14 constexpr support is in a separate row with the signification that has not yet been implemented.
So I guess, we'll have to wait for newer versions where constexpr functionality will be fully implemented.
Visual C++ 2013 does not support constexpr at all. You can use "static const" instead of "static constexpr" for Visual C++.
Edit: This is indeed caused by a bug in Visual Studio - and it has already been fixed. The issue is not reproducible after applying Update 2 to Visual Studio (release candidate available here). I apologize; I thought I was up to date with my patches.
I can't for the life of me figure out why I get a seg fault when I run the following code in Visual Studio 2013:
#include <initializer_list>
#include <memory>
struct Base
{
virtual int GetValue() { return 0; }
};
struct Derived1 : public Base
{
int GetValue() override { return 1; }
};
struct Derived2 : public Base
{
int GetValue() override { return 2; }
};
int main()
{
std::initializer_list< std::shared_ptr<Base> > foo
{
std::make_shared<Derived1>(),
std::make_shared<Derived2>()
};
auto iter = std::begin(foo);
(*iter)->GetValue(); // access violation
return 0;
}
I was expecting the initializer_list to take ownership of the created shared_ptrs, keeping them in scope until the end of main.
Oddly enough, if I try to access the second item in the list, I get the expected behavior. For example:
auto iter = std::begin(foo) + 1;
(*iter)->GetValue(); // returns 2
Considering these things, I'm guessing this may be a bug in the compiler - but I wanted to make sure I wasn't overlooking some explanation for why this behavior might be expected (e.g., maybe in how rvalues are handled in initializer_lists).
Is this behavior reproducible in other compilers, or can someone explain what might be happening?
See the original answer for analysis of object lifetimes of the code in the question. This one isolates the bug.
I made a minimal reproduction. It's more code, but a lot less library code involved. And easier to trace.
#include <initializer_list>
template<size_t N>
struct X
{
int i = N;
typedef X<N> self;
virtual int GetValue() { return 0; }
X() { std::cerr << "X<" << N << ">() default ctor" << std::endl; }
X(const self& right) : i(right.i) { std::cerr << "X<" << N << ">(const X<" << N << "> &) copy-ctor" << std::endl; }
X(self&& right) : i(right.i) { std::cerr << "X<" << N << ">(X<" << N << ">&& ) moving copy-ctor" << std::endl; }
template<size_t M>
X(const X<M>& right) : i(right.i) { std::cerr << "X<" << N << ">(const X<" << M << "> &) conversion-ctor" << std::endl; }
template<size_t M>
X(X<M>&& right) : i(right.i) { std::cerr << "X<" << N << ">(X<" << M << ">&& ) moving conversion-ctor" << std::endl; }
~X() { std::cerr << "~X<" << N << ">(), i = " << i << std::endl; }
};
template<size_t N>
X<N> make_X() { return X<N>{}; }
#include <iostream>
int main()
{
std::initializer_list< X<0> > foo
{
make_X<1>(),
make_X<2>(),
make_X<3>(),
make_X<4>(),
};
std::cerr << "Reached end of main" << std::endl;
return 0;
}
The output is BAD on both x64:
C:\Code\SO22924358>cl /EHsc minimal.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
minimal.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:minimal.exe
minimal.obj
C:\Code\SO22924358>minimal
X<1>() default ctor
X<0>(X<1>&& ) moving conversion-ctor
X<2>() default ctor
X<0>(X<2>&& ) moving conversion-ctor
X<3>() default ctor
X<0>(X<3>&& ) moving conversion-ctor
X<4>() default ctor
X<0>(X<4>&& ) moving conversion-ctor
~X<0>(), i = 2
~X<2>(), i = 2
~X<0>(), i = 1
~X<1>(), i = 1
Reached end of main
~X<0>(), i = 4
~X<0>(), i = 3
~X<0>(), i = 2
~X<0>(), i = 1
and x86:
C:\Code\SO22924358>cl /EHsc minimal.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
minimal.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:minimal.exe
minimal.obj
C:\Code\SO22924358>minimal
X<1>() default ctor
X<0>(X<1>&& ) moving conversion-ctor
X<2>() default ctor
X<0>(X<2>&& ) moving conversion-ctor
X<3>() default ctor
X<0>(X<3>&& ) moving conversion-ctor
X<4>() default ctor
X<0>(X<4>&& ) moving conversion-ctor
~X<0>(), i = 2
~X<2>(), i = 2
~X<0>(), i = 1
~X<1>(), i = 1
Reached end of main
~X<0>(), i = 4
~X<0>(), i = 3
~X<0>(), i = 2
~X<0>(), i = 1
Definitely a compiler bug, and a pretty severe one. If you file a report on Connect I and many others will be happy to upvote.
The shared_ptr objects returned from make_shared are temporaries. They will be destroyed at the end of the full-expression, after being used to initialize shared_ptr<Base> instances.
But ownership of the user objects (the Derived1 and Derived2) should be shared (or "transferred" if you like) to the shared_ptr instances in the list. Those user objects should live until the end of main.
I just ran the code from your question using Visual Studio 2013 and got no access violation. Oddly, when I trace to main() and ~Base(), I get the following output:
C:\Code\SO22924358>cl /EHsc main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
C:\Code\SO22924358>main
~Base()
Reached end of main
~Base()
That does look wrong.
And if I do something with the return value of GetValue(), it is wrong (0 instead of 1) and I get the access violation. It occurs after all tracing output, however. And it seems somewhat intermittent.
C:\Code\SO22924358>cl /Zi /EHsc main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
Microsoft (R) Incremental Linker Version 12.00.21005.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
/debug
main.obj
C:\Code\SO22924358>main
~Base()
GetValue() returns 0
Reached end of main
~Base()
Here's the final version of the code I'm working with:
#include <initializer_list>
#include <memory>
#include <iostream>
struct Base
{
virtual int GetValue() { return 0; }
~Base() { std::cerr << "~Base()" << std::endl; }
};
struct Derived1 : public Base
{
int GetValue() override { return 1; }
};
struct Derived2 : public Base
{
int GetValue() override { return 2; }
};
int main()
{
std::initializer_list< std::shared_ptr<Base> > foo
{
std::make_shared<Derived1>(),
std::make_shared<Derived2>()
};
auto iter = std::begin(foo);
std::cerr << "GetValue() returns " << (*iter)->GetValue() << std::endl; // access violation
std::cerr << "Reached end of main" << std::endl;
return 0;
}
Stepping through shows that destructors are called immediately after initializer list construction for shared_ptr<Derived1> (correct, its object has been moved to a shared_ptr<Base>), and the matching shared_ptr<Base>, which is very very wrong.
When you compile the following C++ source file in Visual Studio 2010 with warning level /W4 enabled
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
if (result = strcmp(str0, str1)) // line 11
{
printf("Strings are different\n");
}
}
you get the following warning
warning C4706: assignment within conditional expression
for line 11.
I want to suppress this warning exactly at this place. So I tried Google and found this page: http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx
So I changed the code to the following - hoping this would solve the problem:
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
#pragma warning(push)
#pragma warning(disable : 4706)
if (result = strcmp(str0, str1))
#pragma warning(pop)
{
printf("Strings are different\n");
}
}
It didn't help.
This variant didn't help either:
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
#pragma warning(push)
#pragma warning(disable : 4706)
if (result = strcmp(str0, str1))
{
#pragma warning(pop)
printf("Strings are different\n");
}
}
To avoid one further inquiry: I cleaned the solution before each compilation. So this is probably not the fault.
So in conclusion: how do I suppress the C4706 exactly at this place?
Edit Yes, rewriting is possible - but I really want to know why the way I try to suppress the warning (that is documented officially on MSDN) doesn't work - where is the mistake?
Instead of trying to hide your warning, fix the issue it's complaining about; your assignment has a value (the value on the left side of the assignment) that can be legally used in another expression.
You can fix this by explicitly testing the result of the assignment:
if ((result = strcmp(str0, str1)) != 0)
{
printf("Strings are different\n");
}
In MSDN Libray: http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx, There is the section as follows.
For warning numbers in the range 4700-4999, which are the ones
associated with code generation, the state of the warning in effect
when the compiler encounters the open curly brace of a function will
be in effect for the rest of the function. Using the warning pragma in
the function to change the state of a warning that has a number larger
than 4699 will only take effect after the end of the function. The
following example shows the correct placement of warning pragmas to
disable a code-generation warning message, and then to restore it.
So '#pragma warning' only works for an each function/method.
Please see the following code for more detail.
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
#pragma warning(push)
#pragma warning( disable : 4706 )
void func()
{
int result;
if (result = strcmp(str0, str1)) // No warning
{
printf("Strings are different\n");
}
#pragma warning(pop)
}
int main()
{
int result;
if (result = strcmp(str0, str1)) // 4706 Warning.
{
printf("Strings are different\n");
}
}
The sane solution is to rewrite the condition to
if( (result = strcmp(str0, str1)) != 0 )
which will inform any C compiler that you really want to assign, and is almost certain to generate the same object code.
There is another solution which avoids the warning: the comma operator.
The main advantage here will be that you don't need parentheses so it's a bit shorter than the !=0 solution when your variable name is short.
For example:
if (result = strcmp(str0, str1), result)
{
printf("Strings are different\n");
}
There is a simple construction !! to cast a type to bool. Like this:
if (!!(result = strcmp(str0, str1)))
However, in some cases direct comparison != 0 might be more clear to a reader.