Why can't I use assert with std::is_same? - c++

Can somebody explain to me why on Earth does this code snippet refuse to work?
#include <cassert>
#include <type_traits>
using namespace std;
int main()
{
assert(is_same<int, int>::value);
}
Compilation fails because, according to the compiler:
prog.cpp:7:33: error: macro "assert" passed 2 arguments, but takes just 1
assert(is_same<int, int>::value);
^
prog.cpp: In function 'int main()':
prog.cpp:7:2: error: 'assert' was not declared in this scope
assert(is_same<int, int>::value);
^
What? is_same<int, int>::value is undoubtedly one argument. Also assert is declared at this scope, and the compiler itself confirmed it in the previous error!
http://ideone.com/LcMVkn

The macro splits your parameter(s) like this:
is_same<int , int>::value
// ^^ par1 ^^// ^^ par2 ^^
As assert() is a macro definition (with one parameter), it's handled by the C-preprocessor. The preprocessor is unaware of c++ syntax like template parameters gouped in angle brackets (<>) separated with ,. So the parameter expression is split up like shown above.
You can avoid that using extra parenthesis, so the C-preprocessor will take that parameter as a whole:
assert((is_same<int, int>::value));
// ^ ^

Related

doctest CHECK_TROWS_AS unused argument

I'd like to doctest some conversion expression with C++ doctest.
I'm using a code similar to the following
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
TEST_CASE("operator int()") {
CHECK_THROWS_AS(int(2), std::invalid_argument);
int i;
CHECK_THROWS_AS(i = int(2), std::invalid_argument);
}
However in both case I get a warning:
dd.cpp:7:7: warning: variable 'i' set but not used [-Wunused-but-set-variable]
int i;
^
dd.cpp:6:19: warning: expression result unused [-Wunused-value]
CHECK_THROWS_AS(int(2), std::invalid_argument);
^ ~
How do I silence the warning in proper C++ (not using a particular compiler feature).
By the way, in my real code, 2 is actually replaced by an object of a class whose int operator may throw.

Error facing with range function in DPC++

I'm new to Sycl/DPC++ language. I wrote a sample vector addition code using Unified shared memory (USM):
#include<CL/sycl.hpp>
#include<iostream>
#include<chrono>
using namespace sycl;
int main()
{
int n=100;
int i;
queue q{ };
range<1>(n);
int *a=malloc_shared<int>(n,q);
int *b=malloc_shared<int>(n,q);
int *c=malloc_shared<int>(n,q);
for(i=0;i<n;i++)
{
a[i]=i;
b[i]=n-i;
}
q.parallel_for(n,[=](auto &i){
c[i]=a[i]+b[i];
}).wait();
for(i=0;i<n;i++){
std::cout<<c[i]<<std::endl;
}
free(a,q);
free(b,q);
free(c,q);
return 0;
}
When I compile it I get the following error:
warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'n' [-Wvexing-parse]
range<1>(n);
^~~
vec_add.cpp:11:1: note: add enclosing parentheses to perform a function-style cast
range<1>(n);
^
( )
vec_add.cpp:11:9: note: remove parentheses to silence this warning
range<1>(n);
^ ~
vec_add.cpp:11:10: error: redefinition of 'n' with a different type: 'range<1>' vs 'int'
range<1>(n);
^
vec_add.cpp:8:5: note: previous definition is here
int n=100;
^
1 warning and 1 error generated.
How to fix this error?
error: redefinition of 'n' with a different type: 'range<1>' vs 'int'
Two variables with the same name within the same scope create confusion to the compiler, so it might be the reason for the error which you are getting. You can try defining the value of n globally say for eg: #define N 100 in this case, set
range<1>(n);
to
range<1> (N);
and use that in your code.
If you want to declare the size locally then assign another variable (r) to the range as
range<1> r (n);
Now you can directly pass the 'r' variable as a parameter to the parallel_for.

Permitted usage context of declarations

The following code
#include <iostream>
#include <memory>
#include <ios>
using std::cout;
using std::endl;
using std::unique_ptr;
using std::make_unique;
using std::boolalpha;
template<typename T>
struct alloc{
alloc();
unique_ptr<T> operator() (void){
return(auto up = make_unique<T>(NULL));
}
};
int main (void){
auto up = alloc<int>()();
cout << boolalpha << ((up) ? 1 : 0) << endl;
return 0;
}
when compiled gives the following error:
g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra -c code.cpp
code.cpp: In member function ‘std::unique_ptr<_Tp> alloc<T>::operator()()’:
code.cpp:14:16: error: expected primary-expression before ‘auto’
return(auto up = make_unique<T>(NULL));
^~~~
code.cpp:14:16: error: expected ‘)’ before ‘auto’
make: *** [makefile:20: code.o] Error 1
There is an earlier question on SO reporting the same error:
C++17 std::optional error: expected primary-expression before 'auto'
The following is a snippet from the accepted answer to the above question:
Declarations are not expressions. There are places where expressions
are allowed, but declararions are not.
So my questions based on the compilation error I get are:
a) Is the use of a declaration in a return statement not permitted by the standard?
b) What are the permitted contexts for declarations?
Note: I had deliberately used the auto keyword in the return statement to reproduce this error. This error had originally appeared in a larger code base.
TIA
Is the use of a declaration in a return statement not permitted by the standard?
Indeed it isn't. We need only examine the grammar production at [stmt.jump]/1
Jump statements unconditionally transfer control.
jump-statement:
break ;
continue ;
return expr-or-braced-init-listopt ;
goto identifier ;
There is no production that turns an "expr-or-braced-init-list" into any sort of statement, so no declaration statement either. There is also no production that turns it into any other sort of declaration (such as a function, namespace or class). So you cannot declare anything in the return statement's operand.
What are the permitted contexts for declarations?
Almost anywhere an expression isn't required explicitly. The very definition of a translation unit in C++ (one file being translated) is a sequence of declarations per [basic.link]/1.
A program consists of one or more translation units linked together. A
translation unit consists of a sequence of declarations.
translation-unit:
declaration-seqopt
Different declarations have different structure. Somes such as namespaces, may contain more declarations. Others such as functions may contain statements, which themselves may be declaration statements of certain things. But most importantly, the standard makes clear where a statement may appear, and where only an expression is permitted.

Why are double parentheses needed with std::is_same [duplicate]

This question already has answers here:
Using commas inside a macro without parenthesis: How can I mix and match with a template?
(3 answers)
Closed 6 years ago.
I was trying to use std::is_same to verify the underlying type of a strongly typed enum and I noticed a strange situation where I needed to use double parentheses, but I don't understand why. I've reduced the example down to as follows:
#include <type_traits>
#include <cassert>
#include <stdint.h>
int main(int argc, char *argv[])
{
assert((std::is_same<unsigned int,uint32_t>::value == true)); // OK
assert((std::is_same<unsigned int,uint32_t>::value) == true); // OK
//assert(std::is_same<unsigned int,uint32_t>::value == true); // Compile error
static_assert(std::is_same<unsigned int,uint32_t>::value == true, "BAD"); // OK
return 0;
}
Compile error:
isSameAssert.cpp:9:62: error: macro "assert" passed 2 arguments, but takes just 1
assert(std::is_same<unsigned int,uint32_t>::value == true); // Compile error
^
isSameAssert.cpp: In function ‘int main(int, char**)’:
isSameAssert.cpp:9:5: error: ‘assert’ was not declared in this scope
assert(std::is_same<unsigned int,uint32_t>::value == true); // Compile error
^
make: *** [build/isSameAssert] Error 1
Could anyone explain this or point me to a reference that does?
Because assert is a macro, the expression assert(std::is_same<unsigned int,uint32_t>::value == true); seems to call assert with two parameters due to the comma between int and uint32_t so the compiler complains that assert takes only one parameter, but two were supplied.
Indeed, putting it again in parenthesis solves this issue.

Template function call ambiguity error

I am not familiar with templates. I've just started learning it. Why I am getting errors in following program?
#include <iostream>
#include <string>
using std::cout;
using std::string;
template<class C>
C min(C a,C b) {
return a<b?a:b;
}
int main()
{
string a="first string";
string b="second string";
cout<<"minimum string is: "<<min(a,b)<<'\n';
int c=3,d=5;
cout<<"minimum number is: "<<min(c,d)<<'\n';
double e{3.3},f{6.6};
cout<<"minimum number is: "<<min(e,f)<<'\n';
char g{'a'},h{'b'};
cout<<"minimum number is: "<<min(g,h)<<'\n';
return 0;
}
Errors:
13 [Error] call of overloaded 'min(std::string&, std::string&)' is ambiguous
6 [Note] C min(C, C) [with C = std::basic_string<char>]
Please help me.
There are a two things going on here.
Your first problem is that you only included part of the error message. Here is a link to the code being complied in gcc and clang, and one of the resulting error messages (in full):
main.cpp:13:34: error: call to 'min' is ambiguous
cout<<"minimum string is: "<<min(a,b)<<'\n';
^~~
/usr/include/c++/v1/algorithm:2579:1: note: candidate function [with _Tp = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
min(const _Tp& __a, const _Tp& __b)
^
main.cpp:6:3: note: candidate function [with C = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
C min(C a,C b) {
^
there are two candidates. One at main.cpp:6:3 (line 6, character 3) and one at algorithm:2579:1 (line 2579, character 1).
One of them you wrote, and one of them in #include <algorithm>.
One of your header files included <algorithm> without you asking for it. The standard headers are allowed to do this, as annoying as it is sometimes.
In <algorithm> there is a std::min function template. As std::string is an instance of a template class in namespace std, the function template std::min is found via a process called "argument dependent lookup" or "Koenig lookup". (function overload candidates are searched for locally, and also in the namespaces of the arguments to the function, and in the namespaces of the template arguments to the arguments to the function, and in the namespaces of the things pointed to by the arguments of the function, etc.)
Your local function min is also found, as it is in the same namespace as the body of main.
Both are equally good matches, and the compiler cannot decide which one you want to call. So it generates an error telling you this.
Both gcc and clang do error: then a sequence of note:s. Usually all of the note:s after an error are important to understanding the error.
To fix this, try calling ::min (fully qualifying the call), or renaming the function to something else, or make your version a better match than std::min (tricky, but doable in some cases), or calling (min)(a,b). The last blocks ADL/Koenig lookup, and also blocks macro expansion (for example, if some OS has injected #define min macros into their system headers) (via # 0x499602D2).
You're running into a name collision with std::min. It is likely included in one of the other standard libary headers that you included, either <iostream> or <string>, my guess is probably the latter. The quick fix is to rename your function. For example, renaming it to mymin works fine. Demo