I wanted to check that the extern keyword did infact prevent class code being generated in the translation unit:
template<class> struct always_false : std::false_type {};
template <typename T> class A{
static_assert(always_false<T>::value, "If this fires, 'A' is instantiated");
};
extern template class A<int>; //error: static assertion failed: If this fires, 'A' is instantiated|
int main(){
// A<int> f;
}
Why is it that the previous code still produces an error from the static_assert if this is my only source file? As far as I understand from the explicit use of extern this should prevent any production of code for the class A<int> and the linker takes care of finding a later explicit instantiation definition (in the translation unit for which the code is actually written) to match any use of A<int> with.
However it seems that the explicit instantiation declaration is generating code in this translation unit itself as indicated by the compilation error. If I comment out extern template class A<int> everything works fine. I was using GCC 4.9.2. but it appears clang 3.5.1 throws this error too.
Alternatively this also kicks up the same assert error:
template<class> struct always_false : std::false_type {};
template <typename T> class A{
public:
void test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }
};
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Here I would've expected the member function A<int>::test() to not even be instantiated and again wait until linking before "finding" code for the function, but it looks like the code is generated in the same translation unit. However if I take out the static_assert:
template <typename T> class A{
public:
void test() { }
};
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Then I get the error I'm expecting, indicating that A<int>::test() is not instantiated and there was a linker error:
**undefined reference to `A<int>::test()'|**
Why would the static_assert throw an error if test() was never instantiated?
Your premise is wrong. extern template prevents object code generation for function templates (including member functions of class templates), but it doesn't prevent the instantiation of the class bodies.
Edit: To answer the updated question: the member function is defined inline in the class, so the compiler will still instantiate it so that it can inline it if necessary. If you define the function out of line, you will not get an error (tried GCC 5.2.0 via godbolt).
#include <type_traits>
template<class> struct always_false : std::false_type {};
template <typename T> class A{
public:
void test();
};
template <typename T>
void A<T>::test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Related
Consider the following code which attempts to implement a partial specialization of class Bar. In the first case, the foo member function is defined inline and in the second case out of line. The out of line definition produces a compile error which I cannot figure out:
error: out-of-line definition of 'foo' from class 'Bar<T>' without definition
template<class T>
struct Bar;
template<class T>
requires std::is_same_v<T, int>
struct Bar<T> {
int foo(T a) {
return a + 5;
}
};
template<class T>
requires std::is_same_v<T, double>
struct Bar<T> {
double foo(T a);
};
template<class T>
requires std::is_same_v<T, double>
double Bar<T>::foo(T a) {
return a + 5;
};
I am using clang-11 with the c++20 compilation option. I am unsure if this is my misunderstanding, a feature or a bug. Any help is appreciated.
Might be clang bug. It was reported at https://bugs.llvm.org/show_bug.cgi?id=50276.
Anyway GCC is fine
Code bellow cause compilation error with msvc (x86 msvc v19.16),
but any other compiler accepts it without error (gcc, clang, icc).
You can see error here godbolt link ,
the error is:
[x86 msvc v19.16 #1] error C2989: 'RustStrView': class template has already been declared as a non-class template
about this line of code template <bool PARAM> inline struct RustStrView Foo<PARAM>::f() {
If I remove struct from struct RustStrView or make Foo not template
class all compiled without errors.
Is this bug in my code (clang/gcc/icc accepts it with -std=c++11 -pedantic)
or this is msvc bug?
Side note this is code is partly generated and it is not simple to teach generator
to call type as struct X inside generated C part and X inside C++.
extern "C" {
struct RustStrView {
unsigned not_important;
};
typedef struct FooOpaque FooOpaque;
struct RustStrView Foo_getName(const FooOpaque *const self);
}
template <bool> class Foo {
public:
struct RustStrView f();
private:
FooOpaque *p_;
};
template <bool PARAM> inline struct RustStrView Foo<PARAM>::f() {
struct RustStrView s = Foo_getName(this->p_);
return s;
}
It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.
I'm seeing an error related to templates (compiler is Visual Studio 2012) that I don't understand. Here's the code, boiled down to the essentials:
// Templated class - generic
template <typename T>
class Test
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// Templated class - expicit specialization for T = int.
template <>
class Test<int>
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// The definition below compiles and works fine at runtime.
template<typename T> void Test<T>::Problem() {}
// The definition below gives error C2910.
template<> void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
For the WorksFine method, the function definition is inside the explicitly specialized class definition, and everything is fine. But for the Problem method, when I define the method outside the explicitly specialized class definition, I get error C2910
Why is this? Error C2910 indicates that the problem is that Test::Problem() is already defined. But it is not defined inside the class...there is no function definition only a declaration.
It seems pretty lame to be able to do something or not depending on where you choose to put the function definition, which I always though was more of a style/syntax decision, not a functionality/semantics decision. Am I missing something?
You don't need the template<>. Just write:
void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
The template<> syntax on a member specialization is required where explicitly instantiating a member on its own; it is omitted when defining a member of an already existing specialization.
template<typename T> struct X { static int i; };
template<> int X<int>::i = 0; // member instantiation, uses template<>
template<typename T> struct Y { static int i; };
template<> struct Y<int> { static int i; } // template specialization
int Y<int>::i = 0; // no template<>
You don't need template anymore in the explicit function definition: void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
In this case g++ gives a slightly better error message error: template-id 'Problem<>' for 'void Test<int>::Problem()' does not match any template declaration
Try this:
// The definition below gives error C2910.
void Test<int>::Problem()
{
printf("In Test::Problem(int instantiation)\n");
}
int main()
{
Test<int> hey;
hey.Problem();
return 0;
};
We have complex template classes that have some methods which will not work with certain policies or types. Therefore, when we detect those types (at compile time, using type-traits) we fire a static assertion with a nice message.
Now we do a lot of manual template instantiation as well. Partly it is so that the methods are forced to compiler to syntax check the methods. It also reduces compile time for the library user. The problem is that the static assertions are always fired and consequently we cannot manually instantiate the template class in question.
Is there a workaround for this?
EDIT: To make it clearer, here is an example (the explicit instantiation in this case will fail on someFunc1():
// header
template <typename T>
class someClass
{
void someFunc() {}
void someFunc1() { static_assert(false, assertion_failed); }
};
// source
template someClass<int>; // Explicit instantiation
EDIT2: Here is another example. This time you can compile it to see what I mean. First compile right away. The code should compile. Then Uncomment [2] and the static assertion should fire. Now comment out [2] and Uncomment [1]. The static assertion will fire because you are explicitly instantiating the template. I want to avoid removing explicit instantiation because of the benefits that come with it (see above for benefits).
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
//template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1();
foo<double> b;
//b.func1(); //[2]
return 0;
}
You can't have both: you can't have a static assertion to prevent instantiation and explicitly instantiate the type! This is an obvious contradiction. What you can have, however, is conditionally included functionality even though it is somewhat a pain in the neck: If a certain member function is not supposed to be supported for certain types, you can move this function into a base class which conditionally has it. This way you wouldn't use a static assertion but just remove the member function. I realize that this introduces interesting other problems, e.g. with respect to the location of member variables, but I think in the context you are describing this is the best you can get.
Here is a quick example of how this could look like:
template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base;
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ };
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } };
template <typename T>
struct Foo: foo_base<T> { /* .... */ };
template struct Foo<int>; // will have foo()
template struct Foo<double>; // will not have foo()
Alright, so if you're forcing the instantiation of all methods using explicit instantiation, you can't get away with any compile time tricks to prevent instantiation of the offending methods, such as enable_if. It'd be easy enough to move the error to runtime, but that's undesirable.
I think the best you can do is move the error to link time, which will statically ensure that the program does not contain a code path that could potentially call the prohibited function, but the error messages won't be very helpful to anyone that doesn't know about the restriction you're imposing. Anyway, the solution is to declare a specialization of the prohibited member functions but not define them:
template<typename T>
struct Foo {
void bar() {
std::cout << "bar\n";
}
void baz() {
std:: cout << "baz\n";
}
};
template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail
template struct Foo<int>;
template struct Foo<char>;
int main() {
Foo<int> f;
f.bar();
// f.baz(); // uncommenting this line results in an ugly link time error
Foo<char> b;
b.bar();
b.baz(); // works with Foo<char>
}
The static asserts no longer help give nice error messages when a mistake is made in client code, but you might want to leave them in because they'll fire if you forget to provide a specialization.
enable_if is a flexible mechanism for precise template methods targeting, may be what you are after. Example:
#include <string>
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
template <class T> class mywrapper
{
T _value;
template <class V>
typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_scalar<V>::value);
std::cout << "scalar: " << value << std::endl;
}
template <class V>
typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_compound<V>::value);
std::cout << "compound: " << value << std::endl;
}
public:
mywrapper(T const& value):_value(value) { }
void printval() { printval_(_value); }
};
template class mywrapper<int>;
template class mywrapper<std::string>;
int main()
{
mywrapper<int> ival(333);
mywrapper<std::string> sval("test");
ival.printval();
sval.printval();
return 0;
}
I did not get an opportunity to test enable_if as suggested by bobah but I did come up with a solution that does not require boost and that satisfies my original requirement to a good extent (I say good and not full, will explain at the end)
The solution is to put a dummy template on the code that will fail if compiled under some selected types and is fine under others. So:
struct dummyStruct {};
#define DUMMY_TEMP typename dummy
#define DUMMY_PARAM dummyStruct
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
template <typename T_Dummy>
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1<DUMMY_PARAM>();
foo<double> b;
//b.func1<DUMMY_PARAM>(); //[2] - this is a static error
return 0;
}
In all of my template code, these kind of functions (i.e. the ones that have static asserts OR work on some types and may fail on others by using type traits [in which case there is a selection of several different functions for different types]) are hidden from the client. So in my implementation, adding the extra dummy parameter is an OK compromise.
As a bonus, it lets me know that this function is designed to be used by only certain types. Furthermore, my original problem of explicit instantiation is solved by this simple technique.