explicit instantiation of function using decltype : work on g++ but not on Visual C++

456 views Asked by At

This codes run on G++, but not on Visual C++.

#include <iostream>
template<typename T> void foo( T& t,int some_parameter){}
template decltype(foo<int>) foo;
int main(){
    std::cout << "Hello, world!\n";
}

Here is the error from Visual C++ :-

error C2206: 'foo': typedef cannot be used for function definition

Incentive : I don't want to repeat function signature for explicit instantiation.
I modified code from https://stackoverflow.com/a/28356212 .

Which one is wrong? How to workaround it in Visual C++?

Current indirect workaround

A day later, here is the best workaround I found : https://stackoverflow.com/a/50350144 .

#include <tuple>
template<typename... Ts>auto instantiate() {
    static auto funcs = std::tuple_cat(std::make_tuple(
        foo1<Ts>,
        foo2<Ts>
    )...);
    return &funcs;
}
template auto instantiate<int, double>();

However, in Visual C++, it works only when compile foo.cpp with optimization turned on :-

  • Custom or Disabled(/Od) is not OK.
  • Use all of /O1, /O2 and /Ox are OK.
  • Without any of /Od, /O1, /O2 and /Ox :-
    • Just /Og is OK.
    • Just /Oi, /Ot, /Oy, /Ob2, /GF and /Gy is not OK.
    • Use all flags in the two above lines is OK.

Workaround of the workaround (work with /Od): Call the std::tuple_size<decltype(instantiate<int, double>())> inside a dummy function in a .cpp. Then declare the dummy function in header.

1

There are 1 answers

0
Passer By On

I believe msvc is wrong. In short, an explicit instantiation is simply a template followed by your typical declaration.

If you follow the grammar [temp.explicit]

explicit-instantiation:
    template declaration
declaration:
    block-declaration
block-declaration:
    simple-declaration
simple-declaration:
    decl-specifier-seq init-declarator-list;
decl-specifier-seq:
    decl-specifier
decl-specifier:
    defining-type-specifier
defining-type-specifier:
    simple-type-specifier
simple-type-specifier:
    decltype-specifier
decltype-specifier:
    decltype ( expression )

I don't believe there is a work around for this. Apparently, msvc considers decltype as a type alias, and rejects any "perceived" definitions with signatures that are aliases. These are rejected as well

using F = decltype(foo<int>);
template F foo;
extern template F foo;  // not even a definition

Yet it accepts these

F bar;
decltype(foo<int>) baz;