I haven't written many C++ templates till recently, but I'm trying to take a deep dive into them. Fixing one developer's code I managed to produce some compiler behavior that I can't explain. Here is the simplified program. ( When I try to simplify more, I lose that "strange" behavior). Let's think of some class Depender, which is a parameter of template struct Dependency. Depender
can depend on the List of Dependee
s. I have some macros that can produce specializations of the Dependency
template. Dots in the following code block stand for the possible macro expansion. I have a forward-declared MainDependee before dots, and MainDependee's definition after dots.
#include <type_traits>
template <typename T, typename = void>
struct IsCompleteType : std::false_type
{};
template <typename T>
struct IsCompleteType<T, std::enable_if_t<( sizeof( T ) > 0 )>> : std::true_type
{};
template<template<typename...> class List, typename Dependee>
struct DependencyInternal
{
using Type = std::conditional_t<IsCompleteType<Dependee>::value, Dependee, Dependee>;
};
template<typename... Ts> class StubList;
class MainDependee; // forward declaration
class MainDepender
{};
template<template<typename...> class List, typename Depender>
struct Dependency;
....... //here is the specialization
class MainDependee {};
int main()
{
Dependency<StubList, MainDepender> a;
}
When the dots are replaced with
template<template<typename... Us> class List>
struct Dependency<List, MainDepender>
{
using Type = typename DependencyInternal<List, MainDependee>::Type;
};
then in main
I get IsCompleteType<MainDependee>::value == true
.
But when the dots are replaced with
template<>
struct Dependency<StubList, MainDepender>
{
using Type = typename DependencyInternal<StubList, MainDependee>::Type;
};
then IsCompleteType<MainDependee>::value == false
.
Please tell me, what rule describes the difference between these options?