Default template argument in a function: reasonable but disallowed

  • Thread starter chrisstankevitz
  • Start date
C

chrisstankevitz

Apparently default template arguments can only be used in classes. I
include two apps below. One works but is IMO messy. The other does
not work and is IMO clean.

Q1: Why would c++ dissallow the clean version?
Q2: Is there a way to do what I want to do "cleanly" (as I define it :)

The templated function writes a long to a binary stream in 64 bits.
This code works for 32 and 64 bit long.

Thanks!

Chris

//===== This code is messy, allows for user error, but compiles =====

#include <fstream>

template<typename Type, int NumBits>
void BinaryWrite64Bit(Type Value, std::eek:stream& Stream);

template<>
void BinaryWrite64Bit<long, 32>(long Value, std::eek:stream& Stream)
{
static const long Zero = 0;
Stream.write(reinterpret_cast<const char*>(&Zero), sizeof(Zero));
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

template<>
void BinaryWrite64Bit<long, 64>(long Value, std::eek:stream& Stream)
{
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

int main()
{
std::eek:fstream Stream;

long Value = 10;

BinaryWrite64Bit<long, sizeof(long)*8>(Value, Stream);

return 0;
}

//===== This code is clean, robust but doesn't compile =====
#include <fstream>

template<typename Type, int NumBits = sizeof(Type)*8>
void BinaryWrite64Bit(Type Value, std::eek:stream& Stream);

template<>
void BinaryWrite64Bit<long, 32>(long Value, std::eek:stream& Stream)
{
static const long Zero = 0;
Stream.write(reinterpret_cast<const char*>(&Zero), sizeof(Zero));
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

template<>
void BinaryWrite64Bit<long, 64>(long Value, std::eek:stream& Stream)
{
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

int main()
{
std::eek:fstream Stream;

long Value = 10;

BinaryWrite64Bit(Value, Stream);

return 0;
}
 
M

mlimber

Apparently default template arguments can only be used in classes. I
include two apps below. One works but is IMO messy. The other does
not work and is IMO clean.

Q1: Why would c++ dissallow the clean version?
Q2: Is there a way to do what I want to do "cleanly" (as I define it :)

The templated function writes a long to a binary stream in 64 bits.
This code works for 32 and 64 bit long.

Thanks!

Chris

//===== This code is messy, allows for user error, but compiles =====

#include <fstream>

template<typename Type, int NumBits>
void BinaryWrite64Bit(Type Value, std::eek:stream& Stream);

template<>
void BinaryWrite64Bit<long, 32>(long Value, std::eek:stream& Stream)
{
static const long Zero = 0;
Stream.write(reinterpret_cast<const char*>(&Zero), sizeof(Zero));
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

template<>
void BinaryWrite64Bit<long, 64>(long Value, std::eek:stream& Stream)
{
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

int main()
{
std::eek:fstream Stream;

long Value = 10;

BinaryWrite64Bit<long, sizeof(long)*8>(Value, Stream);

return 0;
}

//===== This code is clean, robust but doesn't compile =====
#include <fstream>

template<typename Type, int NumBits = sizeof(Type)*8>
void BinaryWrite64Bit(Type Value, std::eek:stream& Stream);

template<>
void BinaryWrite64Bit<long, 32>(long Value, std::eek:stream& Stream)
{
static const long Zero = 0;
Stream.write(reinterpret_cast<const char*>(&Zero), sizeof(Zero));
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

template<>
void BinaryWrite64Bit<long, 64>(long Value, std::eek:stream& Stream)
{
Stream.write(reinterpret_cast<const char*>(&Value), sizeof(Value));
}

int main()
{
std::eek:fstream Stream;

long Value = 10;

BinaryWrite64Bit(Value, Stream);

return 0;
}

How about using a dispatcher to automatically select an implementation:

template<typename Type, int NumBits>
void BinaryWrite64BitImpl(Type, std::eek:stream&);

template<>
void BinaryWrite64BitImpl<long, 32>(
const long value,
std::eek:stream& stream)
{
// ...
}

template<>
void BinaryWrite64BitImpl<long, 64>(
const long value,
std::eek:stream& stream)
{
// ...
}

template<typename Type>
void BinaryWrite64Bit(
const Type value,
std::eek:stream& stream)
{
BinaryWrite64BitImpl
<
Type,
sizeof(Type)*CHAR_BIT
>( value, stream );
}

int main()
{
std::eek:fstream Stream;
const long Value = 10;
BinaryWrite64Bit(Value, Stream);
return 0;
}

Cheers! --M
 
C

chrisstankevitz

mlimber said:
How about using a dispatcher to automatically select an implementation:

Wow, that is cool, never saw that before. Thanks mlimber!

I'm off to see where CHAR_BIT is defined (never saw that either)...

Chris
 
S

Salt_Peter

Wow, that is cool, never saw that before. Thanks mlimber!

I'm off to see where CHAR_BIT is defined (never saw that either)...

Chris

Yep, cool.
You'll find it in climits typically, although you might need to dig
down to limits.h

/* # of bits in a char */
# define CHAR_BIT 8
 
G

Greg

Apparently default template arguments can only be used in classes. I
include two apps below. One works but is IMO messy. The other does
not work and is IMO clean.

Q1: Why would c++ dissallow the clean version?

Apparently there is no good reason.
Q2: Is there a way to do what I want to do "cleanly" (as I define it :)

Yes - compile your program with a C++0x compiler (may require a trip to
the future). The next major version of C++ does allow function
templates to specify default template type parameters.

Greg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top