Fixing warning "Wundefined-var-template" - c++11

Searching for duplicates currently gives:
This post which specifically treats the case of a Singleton implementation, and in which the answers avoids the warning altogether with a different implementation.
This post which answers itself without solving the issue.
A suggested duplicate which explains how to implement template member functions (not relevant).
Another suggested duplicate explaining how to define template static members (not relevant).
As far as I understand, none of these answers the question of how to get rid of Wundefined-var-template with clang++ 3.8+ in a situation similar to the MCVE below?
File a.h
#ifndef A_INCLUDED
#define A_INCLUDED
template <class T>
struct A
{
static const char *name;
};
#endif
File a.cpp
#include "a.h"
template <> const char* A<double>::name = "Johnny";
template <> const char* A<float>::name = "Dude";
File b.cpp
#include <cstdio>
#include "a.h"
void say_it() {
printf( "%s\n", A<double>::name );
}
Run from a terminal:
$ clang++ -c -o a.o -std=c++11 a.cpp
$ clang++ -c -o b.o -std=c++11 b.cpp a.o
clang: warning: a.o: 'linker' input unused [-Wunused-command-line-argument]
b.cpp:5:32: warning: instantiation of variable 'A<double>::name' required here, but no definition is available [-Wundefined-var-template]
printf( "%s\n", A<double>::name );
^
./a.h:7:28: note: forward declaration of template entity is here
static const char *name;
^
b.cpp:5:32: note: add an explicit instantiation declaration to suppress this warning if 'A<double>::name' is explicitly instantiated in another translation unit
printf( "%s\n", A<double>::name );
^
1 warning generated.
Demo

Do as warning message explain, add (in a.h):
template <> const char* A<double>::name;
Demo

Related

Weird C library linkage issues on Mac - Segmentation Fault

I have a strange segmentation fault that doesn't exist when everything is in 1 .c file, but does exist when I put part of the code in a dynamically linked library and link it to a test file. The complete code for the working 1 .c file code is at the bottom, the complete code for the error system with 2 .c and 1 .h file come first.
Here is the error system:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c:
This is essentially a test file:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
Makefile:
I link example to example2 here, and run:
example:
#clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
#clang example2.c example.dylib -o example2.o
#./example2.o
.PHONY: example
The output is:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
But it should show the full output of:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
The weird thing is everything works if it is this system:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
Makefile:
example:
#clang -o example example.c
#./example
.PHONY: example
Wondering why it's creating a segmentation fault when it is linked like this, and what I am doing wrong.
I have checked otool and with DYLD_PRINT_LIBRARIES=YES and it shows it is importing the dynamically linked libraries, but for some reason it's segmentation faulting when linked but works fine when it isn't linked.
Your problem is this, in example.h:
MYARRAY *collection;
Since both main.c and example.c include this file, you end up defining collection twice, which results in undefined behavior. You need to make sure you define each object only once. The details are relatively unimportant since anything can happen with undefined behavior, but what's probably happening is that main.c is allocating memory for one object, but the one example.c is using is still NULL. As mentioned in the comments, since you define collection in main.c your linker is able to build the executable without needing to look for that symbol in the dynamic library, so you don't get a link time warning about it being defined there too, and obviously there'd be no cause for a warning at the time you compile the library.
It works for you when you put everything in one file because obviously then you're not defining anything twice, anymore. The error itself is nothing to do with the fact you're using a dynamic library, although that may have made it harder to detect.
It would be better to define this in example.c and provide a constructor function, there's no need for main() to be able to access it directly. But if you must do this, then define it in example.c and just declare an extern identifier in the header file to tell main.c that the object is defined somewhere else.

Strange behavior with gcc and inline

I want to define an inline function in a header file (.h) which can be included by numerous source files (.c). Here is a minimal example with 1 header and 2 source files:
Header file foo.h
int ifunc(int i);
extern inline
int
ifunc(int i)
{
return i + 1;
}
Source code file: foo.c
#include <stdio.h>
#include "foo.h"
int foo2(int i);
int main()
{
printf("%d\n", foo2(1));
return 0;
}
Source code file foo2.c
#include "foo.h"
int foo2(int i)
{
return ifunc(i);
}
The problem
When I compile with optimization,
gcc -g -Wall -O2 -o foo foo.c foo2.c
$ ./foo
2
everything works fine. However when I turn off optimization, I get this error:
gcc -g -Wall -o foo foo.c foo2.c
/tmp/cc3OrhO9.o: In function `foo2':
foo2.c:5: undefined reference to `ifunc'
Can someone please explain how to fix so that I can run the code with and without -O2? I am using gcc 4.8.5.
if you replace foo.h with
static inline int ifunc(int i)
{
return i + 1;
}
Both will work.
Declaring it extern means it'll be defined somewhere else which in your original example does not happen. And the optimized build doesn't flag as an error because it already optimized it to be inline it but the non-optimized build does not find a definition in any of the .o files (since they were all compiled with ifunc being an extern as defined in foo.h).
Declaring as static inline will ensure that it is local to each file (the downside being that if it does not inline it, you'll end up with each .o that needs it having a local copy, so don't overdo it).

Cuda C++ template undefined reference Compilation issue while porting a visual studio project to linux

I am trying to compile the following code ([cuShiftOr]) to a linux box. Original code is running on Visual Studio 2013 in Windows.
My strategy is to compile all .cu files like below:
nvcc -std=c++11 -Icpp11-range -gencode=arch=compute_52,code=\"sm_52,compute_52\" --use-local-env --cl-version 2013 -maxrregcount=0 --machine 64 --compile -cudart static -DWIN32 -DWIN64 -DNDEBUG -D_CONSOLE -D_MBCS -I$HOME/cuShiftOr/CuShiftOr -I$HOME/cuShiftOr/CuShiftOrBenchmark -I$HOME/cuShiftOr/tinyformat -Xcompiler "-fPIC -fexceptions -ffunction-sections -fdata-sections -fpermissive" -ccbin=/opt/cray/pe/craype/2.5.10/bin/CC -c CuShiftOr/device/hybrid.cu -o objs/CuShiftOr/device/hybrid.cu.o
Likewise for the rest.
At the final stage link everything together by running:
nvcc -std=c++11 -Icpp11-range -gencode=arch=compute_52,code=\"sm_52,compute_52\" --use-local-env --cl-version 2013 -maxrregcount=0 --machine 64 -cudart static -DWIN32 -DWIN64 -DNDEBUG -D_CONSOLE -D_MBCS -I$HOME/cuShiftOr/CuShiftOr -I$HOME/cuShiftOr/CuShiftOrBenchmark -I$HOME/cuShiftOr/tinyformat -Xcompiler "-fPIC -std=c++11 -Icpp11-range -fexceptions -ffunction-sections -fdata-sections -fpermissive -Wnon-template-friend" -ccbin=/opt/cray/pe/craype/2.5.10/bin/CC -o CuShiftOrBenchmark.a objs/CuShiftOr/device/hybrid.cu.o objs/CuShiftOr/util/op.cu.o objs/CuShiftOr/device/segment.cu.o objs/CuShiftOr/host.cu.o objs/CuShiftOr/util/timer.cu.o objs/CuShiftOr/util/file.cu.o objs/CuShiftOr/util/generator.cu.o objs/CuShiftOrBenchmark/kernel.cu.o -lm
However that leads me this undefined reference issue:
objs/CuShiftOrBenchmark/kernel.cu.o: In function `void run_benchmark<unsigned int>(std::ostream&, cushiftor::device::Handler<unsigned int>*, long, unsigned int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
tmpxft_00003ea2_00000000-4_kernel.cudafe1.cpp:(.text._Z13run_benchmarkIjEvRSoPN9cushiftor6device7HandlerIT_EEljiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_Z13run_benchmarkIjEvRSoPN9cushiftor6device7HandlerIT_EEljiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x203): undefined reference to `cushiftor::util::op::bit<unsigned int>::size'
collect2: error: ld returned 1 exit status
inside op.cuh it is defined as:
template<typename type>
struct bit {
static const int size = sizeof(type) * 8;
};
template<typename word>
__host__ __device__ __forceinline__ word ones(int m) {
return ~word(0) >> (bit<word>::size - m);
}
and then on kernel.cu we have:
#include "util/op.cuh"
using cushiftor::util::op::bit;
using cushiftor::util::op::bytepack;
using cushiftor::util::op::div_up;
using cushiftor::util::op::round_up;
using cushiftor::util::op::shuffle_up;
Further more compiling with Visual Studio 2013 (which works since the project was made on that) shows some instantiations that I am not sure if g++ is doing e.g:
2>C:/Users/A/Desktop/cuShiftOr/CuShiftOrBenchmark/kernel.cu(209): warning C4244: 'argument' : conversion from 'int64_t' to 'cushiftor::env::datasize_t', possible loss of data
2> C:/Users/A/Desktop/cuShiftOr/CuShiftOrBenchmark/kernel.cu(230) : see reference to function template instantiation 'void benchmark_with_file<word>(cushiftor::device::Handler<word> *)' being compiled
2> with
2> [
2> word=unsigned int
2> ]
2>C:/Users/A/Desktop/cuShiftOr/CuShiftOrBenchmark/kernel.cu(86): warning C4018: '<=' : signed/unsigned mismatch
2> C:/Users/A/Desktop/cuShiftOr/CuShiftOrBenchmark/kernel.cu(132) : see reference to function template instantiation 'void run_benchmark<word>(std::ostream &,cushiftor::device::Handler<word> *,int64_t,cushiftor::env::datasize_t,int,std::string)' being compiled
2> with
2> [
2> word=unsigned int
2> ]
Now my C++11 template knowledge is very limited but I did try to instantiate also inside the kernel.cu by adding:
template class cushiftor::util::op::bit<unsigned int>;
However to no avail... Any tips are very welcomed!
I believe this question is essentially a duplicate of this one. However simply marking it as such with no explanation may be a bit obscure. Therefore I'm going to provide a CW answer in the hopes that someone may improve it or correct me if I am wrong.
A possible MCVE derived from the code is as follows (note that I'm converting to using g++ directly rather than nvcc, as the manifestation and workarounds are the same):
$ cat test.cpp
#include <iostream>
namespace cushiftor {
namespace util {
namespace op {
template<typename type>
struct bit {
static const int size = sizeof(type) * 8;
};
}
}
}
#ifdef FIX2
void f(const int data){
#else
void f(const int &data){
#endif
std::cout << "size of type in bits is: " << data << std::endl;
}
using cushiftor::util::op::bit;
#ifdef FIX1
template <typename T> const int bit<T>::size;
#endif
template<typename word>
void run_benchmark() {
f(bit<word>::size);
}
int main(){
run_benchmark<unsigned>();
}
$ g++ -o test test.cpp
/tmp/ccCW51e3.o: In function `void run_benchmark<unsigned int>()':
test.cpp:(.text._Z13run_benchmarkIjEvv[_Z13run_benchmarkIjEvv]+0x5): undefined reference to `cushiftor::util::op::bit<unsigned int>::size'
collect2: error: ld returned 1 exit status
$ g++ -DFIX1 -o test test.cpp
$ g++ -DFIX2 -o test test.cpp
$
This MCVE was created based on inspection of relevant code in kernel.cu, tinyformat.h, and op.cuh, in the original cuShiftOr project (and paper).
We see that if we compile the code as-is, it generates a similar error to that reported in the question.
Compiling with -DFIX2 demonstrates that taking the item in question (bit::size) as a reference argument is essential to witnessing of the issue.
Compiling with -DFIX1 eliminates the issue, and I believe is the correct approach in this case.
The explanation for this issue seems to be that the compiler may treat the static const member as a compile-time constant, unless it is "used" in the code. ("Used" has a special language-specific meaning here.) If it is "used" in the code, then the compiler must be able to take the address of it (sensible in the case of a reference parameter) and to take the address of it, the class/struct definition is not sufficient. (It is apparently only a declaration even though it appears in the class/struct definition. The declaration is sufficient for usage equivalently to a compile-time constant, but is not sufficient for the case where we wish to take the address of it.)
From here:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19) In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program
I believe the FIX1 code modification satisfies the bolded requirement above.
With the above preamble, I believe it is valid to mark this as a duplicate.
With respect to the behavior of the original project on windows, I would conjecture that compilers may have leeway in enforcement of this, and may in fact provide referenceable member symbols even when the program does not explicitly define them.

Why can't I specialize std::tuple_element?

The following program attempts to provide a specialization for std::tuple_element for the user-defined type foo. Unfortunately, clang-3.5 rejects it with libc++, but using other compilers or using other standard libraries with clang-3.5 accept the program. Is it correct? If no, why not?
#include <utility>
struct foo {};
namespace std
{
template<size_t, class> struct tuple_element;
template<size_t i>
struct tuple_element<i, foo> {};
}
int main()
{
return 0;
}
Compiler output:
$ clang-3.5 -std=c++11 -stdlib=libc++ -lc++ test.cpp
test.cpp:11:8: error: explicit specialization of non-template struct 'tuple_element'
struct tuple_element<i, foo> {};
^ ~~~~~~~~
1 error generated.
$ clang-3.5 -std=c++11 -lstdc++ test.cpp
(no error)
$ g++-4.9 -std=c++11 test.cpp
(no error)
libc++'s entities are actually in std::__1::, an inline namespace inside std. So your own forward declaration template<size_t, class> struct tuple_element; actually declares a different class template, and then the partial specialization blows up due to ambiguity (though the error message is misleading).
Remove the forward declaration and it should work.

communication between a cpp file and an h file

Please consider the following
/*utils.h*/
#include <cstdio>
#include <iostream>
//#include some other files, including <string>
//ifndef ... and such macro
extern string configpath;
extern void writelog(string, string);
extern string get_fromfile(string, string);
//end the said macro
then we have
/*utils.cpp*/
//all necessary includes, including <string>
#include "utils.h" //they are in the same folder, as the following main .cpp
void writelog(string msg, string location = "lookinconfigfile")
{
if (location == "lookinconfigfile")
{
get_fromFile(configpath, "logpath");
//the function correctly returns the path to logfile, tested separatly.
}
...
}
string get_formFile(string flpt, string wht)
{...}
then in main.cpp, i include utils.h, and set the configpath to point to a file which holds a path to the logfile.
now g++ -c utils.cpp -std=c++11 produces utils.o
g++ -c main.cpp -std=c++11 produces main.o
before introducing the configpath as a global variable, by explicitly mentioning the configpath, that is, hard coding it to each occurrence, i was able to do this:
g++ main.o -o main
and that would generate main as an executable which would behave as expected.
But now i get this:
main.o: In function `writelog(std::string, std::string)':
main.cpp:(.text+0x2ce): undefined reference to `configpath
Also, if i keep the definition of get_fromFile in utils.cpp _after_ writelog, despite the prototype in utils.h, i get that get_fromFile is not defined.
where do i search looking for solutions?
edit: as user2079303 suggested, yes, it is utils.h, not utils.cpp, thank you.
edit2: as bobah mentioned, i actually have the cases correct in my code, just mistyped here. sorry.
You need to define your variable to let compiler know which object file to put it to. Mentioning it in the header file as extern string configpath; just tell compiler that somewhere there will be this variable, leave unresolved reference and let linker resolve it.
Add to your main.cpp:
string configpath;
In your final invocation to gcc, you only link main.o, but not utils.o.

Resources