[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Explicite Template Instantiation and Inline
From: |
Paul Pluzhnikov |
Subject: |
Re: Explicite Template Instantiation and Inline |
Date: |
Sat, 19 May 2007 15:36:14 -0700 |
User-agent: |
Gnus/5.1006 (Gnus v5.10.6) XEmacs/21.4 (Jumbo Shrimp, linux) |
tthunder@gmx.de writes:
> Can anybody think about another possibility?
Ok, I think your requirements are:
- compile-time error if modulo<bool>(bool, bool) is ever called.
- foo<bool> explicitly instantiated (because it must be exported).
- foo<T>::operator=(const T&) calls modulo<T>(T, T)
The "standard" answer is to use type traits.
Here is an "example" solution (works with g++ 3.3.3 and 4.2.0,
you'll have to check whether it works with VC71 yourself).
$ cat foo.h
template <bool X> void compile_time_assert()
{
char buf[X ? 2 : 0]; // fails to compile if X==false
return;
}
template <typename T> struct type_traits {
static const bool is_bool = false;
};
template <> struct type_traits<bool> {
static const bool is_bool = true;
};
template <typename T> T modulo(T a, T b)
{
compile_time_assert< type_traits<T>::is_bool == false>();
// the rest of modulo computation
return a % b;
}
template <typename T> struct foo {
inline foo<T>& operator=(const T&);
T other();
T another();
private:
T m_x;
};
template <typename T> T foo<T>::other() { }
template <typename T> T foo<T>::another() { }
// other non-inline foo<T>:: methods go here ...
#ifdef INSTANTIATE_FOO
template struct foo<bool>;
template struct foo<int>;
template struct foo<long>;
#else
template <typename T>
foo<T>& foo<T>::operator=(const T& x)
{
m_x = modulo<T>(m_x, x);
return *this;
}
// other inline foo<T>:: methods go here ...
#endif
$ cat main.cpp
#define INSTANTIATE_FOO
#include "foo.h"
int main() { return 0; }
This compiles and links just fine, and provides non-inlined instances:
$ g++ -c main.cpp && nm -C main.o && g++ main.o && echo ok
00000000 T main
00000000 W foo<bool>::other()
00000000 W foo<bool>::another()
00000000 W foo<int>::other()
00000000 W foo<int>::another()
00000000 W foo<long>::other()
00000000 W foo<long>::another()
ok
Now let's what the "client" code that actually uses foo<T>
looks like.
$ cat client.cpp
#include "foo.h"
void fn1()
{
foo<int> f;
f = 1;
}
#ifdef BUG
void fn2()
{
foo<bool> f;
f = true;
}
#endif
$ g++ -c client.cpp && nm -C client.o
00000000 W void compile_time_assert<true>()
00000000 T fn1()
00000000 W int modulo<int>(int, int)
00000000 W foo<int>::operator=(int const&)
Good so far: it compiled; it defined (weak) inline functions.
Now let's see what happens if the client tries to use "prohibited"
interface:
$ g++ -c client.cpp -DBUG
foo.h: In function `void compile_time_assert() [with bool X = false]':
foo.h:17: instantiated from `T modulo(T, T) [with T = bool]'
foo.h:46: instantiated from `foo<T>& foo<T>::operator=(const T&) [with T =
bool]'
client.cpp:13: instantiated from here
foo.h:3: error: creating array with size zero (`0')
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.