1

Consider the following code:

#include <vector>
#include <algorithm>

template<typename T, typename R, typename Op>
inline
std::vector<T>
transform_inline(const R & collection, Op op)
{
   std::vector<T> result;

   std::transform
   (
      std::begin(collection),
      std::end(collection),
      std::back_inserter(result),
      op
   );

   return result;
}

extern "C"
{
    void myFunc()
    {
        std::vector<std::pair<double,int>> data;

        transform_inline<double>
        (
            data,
            [](auto & o){ return o.first; }
        );
    }
}

It compiles in gcc and clang, but visual studio says:

<source>(31): error C2894: templates cannot be declared to have 'C' linkage
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.
Compiler returned: 2

See: https://godbolt.org/g/vGvL4t

That error is normally for when you define the template in the extern "C" block, which is obviously not the case here.

Seems like a visual studio bug...Am I correct?

Any known workarounds?

user109078
  • 906
  • 7
  • 19

1 Answers1

2

I would not mix declarations and definitions. Below is the compilable code.

#include <vector>
#include <algorithm>

template<typename T, typename R, typename Op>
inline
std::vector<T>
transform_inline(const R & collection, Op op)
{
   std::vector<T> result;

   std::transform
   (
      std::begin(collection),
      std::end(collection),
      std::back_inserter(result),
      op
   );

   return result;
}

extern "C"
{
    void myFunc();
}

void myFunc()
{
    std::vector<std::pair<double,int>> data;

    transform_inline<double>
    (
        data,
        [](auto & o){ return o.first; }
    );
}

See: https://godbolt.org/g/PbQcFC

273K
  • 29,503
  • 10
  • 41
  • 64
  • Does this work as intended though? I remember something about extern "C" being part of the type system, so you end up with a C++ function and an undefined C one. So calling myFunc from a C program will end up in a linker error. – DeiDei Feb 21 '18 at 16:40
  • 1
    @DeiDei I hope you find answer on your question here https://stackoverflow.com/questions/1380829/is-extern-c-only-required-on-the-function-declaration Please be kind to upvote the answer there. – 273K Feb 21 '18 at 16:43
  • @DeiDei: `[C++14: [dcl.link]/5]:` _"A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration."_ and I take this to include the later declaration that's part of the definition – Lightness Races in Orbit Feb 21 '18 at 16:49
  • In fact I don't have much need for C linkage but I believe this is the recommended approach anyway. – Lightness Races in Orbit Feb 21 '18 at 16:51
  • 1
    @user109078 I would not agree that it is a bug. `auto` in functional parameters could be considered as syntax sugar of templates. It is a Microsoft compiler feature. – 273K Feb 21 '18 at 16:53
  • Hmm true I guess 7.5/4 is picking up the generic lambda – Lightness Races in Orbit Feb 21 '18 at 16:55
  • I had to replace the `auto` in the lambda by `const std::pair`. (VS2013 doesn't like the `auto`, me too.) After this modification, this compiled fine in VS2013. – Scheff's Cat Feb 21 '18 at 16:56
  • 1
    @Scheff VS2013 is another case. VS2013 supports C++11, but `auto` in lambdas can be used since C++14. – 273K Feb 21 '18 at 16:59
  • @S.M. This was not meant as complaint - just a statement of mine. I know that my old VS2013 is a little bit behind... ;-) (And, actually, even C++11 is only partly supported in VS2013 what sometimes hurts.) – Scheff's Cat Feb 21 '18 at 17:01