Last active
January 24, 2023 04:03
-
-
Save davidberard98/96b0b0e71b89406ddaba3e6849d434c0 to your computer and use it in GitHub Desktop.
Explicit template specialization: demonstrating that the presence of a generic implementation can cause errors when an explicit template specialization exists. See run.sh for description
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdexcept> | |
class Base { | |
public: | |
virtual void run() = 0; | |
}; | |
template<int val> | |
class Derived final : public Base { | |
public: | |
#ifdef DEFINE_RUN | |
void run() override { | |
throw std::runtime_error("Unimplemented"); | |
} | |
#else | |
void run() override; | |
#endif | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "def.h" | |
int main() { | |
Derived<2> d; | |
d.run(); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Building a single artifact main_single | |
Running ./main_single (it should run fine): | |
> two | |
Build specialized_unimpl.o | |
Make it into a shared library specialized_unimpl.so | |
Build ./main_unimpl | |
Run ./main_unimpl | |
> two | |
Build specialized_impl.o | |
Make it into a shared library specialized_impl.so | |
Build ./main_impl | |
Run ./main_impl | |
terminate called after throwing an instance of 'std::runtime_error' | |
what(): Unimplemented | |
run.sh: line 20: 548969 Aborted (core dumped) LD_LIBRARY_PATH=`pwd` ./main_${SUFFIX} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file runs the test and has documentation. | |
# The general problem we were having is described below. | |
# We define | |
# class A{ virtual void run() = 0; }; | |
# template<int val> class B : public A { void run() override { throw exception } }; | |
# template<> B<2>::run() {cout << "implemented" << endl;} // and some other <3>, <4>, defined... | |
# Somehow, we call B<unknown>::run() and get the exception thrown. | |
# But when we remove the implementation of B::run (i.e. just leave it as `void run() override;`) | |
# we get "implemented". How is that possible? (i.e. how can we get an exception, but we don't have | |
# a compiler error when we remove the `{ throw exception }` definition? | |
# Turns out, we can repro this when we compile the `B<2>::run()` separately in a shared library... | |
# Below demonstrates this. | |
# def.h: header file containing (a) base class and (b) derived class implementation. | |
# Derived<2>::run() can return an exception or remain unimplemented depending on the scenario. | |
# specialized.cpp: contains a definition of an explicit template specialization for Derived<2> | |
# main.cpp: uses Derived<2> | |
### SINGLE ARTIFACT ### | |
echo "Building a single artifact main_single" | |
g++ main.cpp specialized.cpp -o main_single | |
echo -e "Running ./main_single (it should run fine):" | |
./main_single | |
echo -e '\n' | |
function build_shared () { | |
ARGS=$1 | |
SUFFIX=$2 | |
echo "Build specialized_${SUFFIX}.o" | |
g++ -c -fPIC specialized.cpp ${ARGS} -o specialized_${SUFFIX}.o | |
echo "Make it into a shared library specialized_${SUFFIX}.so" | |
g++ $ARGS -shared -o libspecialized_${SUFFIX}.so specialized_${SUFFIX}.o | |
echo "Build ./main_${SUFFIX}" | |
g++ -L`pwd` -lspecialized_${SUFFIX} main.cpp $ARGS -o main_${SUFFIX} | |
echo "Run ./main_${SUFFIX}" | |
LD_LIBRARY_PATH=`pwd` ./main_${SUFFIX} | |
} | |
### MULTIPLE ARTIFACT, DOES NOT HAVE DEFAULT IMPLEMENTATION OF RUN() | |
build_shared "" "unimpl" | |
echo -e '\n' | |
### MULTIPLE ARTIFACT, HAS DEFAULT IMPLEMENTATION OF RUN() | |
build_shared "-DDEFINE_RUN" "impl" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "def.h" | |
#include <iostream> | |
template<> | |
void Derived<2>::run() { | |
std::cout << " > two" << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment