0
votes

I'm trying to work out under what circumstances the following code might cause a violation of the one-definition rule.

header.h

#pragma once

#include <cstddef>

template<typename T, typename U>
class C {
 friend std::size_t f() {
  // Uses the template parameter that doesn't change
  return sizeof(T); 
 }

 friend std::size_t g() {
  // Uses the template parameter that does change
  return sizeof(U);
 }

 friend std::size_t h() {
  // Does not refer to template parameters
  return 0;
 }
};

// Declarations to help name lookup
std::size_t f();
std::size_t g();
std::size_t h();

src1.cpp

#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, double>;

src2.cpp

#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, float>;

I've explicitly instantiated two different versions of the C class template in the two different translation units. If I link the translation units together, do I have ODR violations?

It seems obvious that there would be an ODR violation for g() because it has a different implementation in each translation unit.

But what about f() and h()? The implementation (i.e. token stream) of each will remain unchanged between translation units. But they are both implicitly making use of different instantiations of C. Does that make a difference? There is no name-lookup happening here is there?

1

1 Answers

1
votes

A function that is defined as part of a friend declaration is implicitly an inline function, so there is no ODR violation as long as all of the definitions are the same in all translation units. It is not a member of the class that it is a friend of, but is a global function, similar to declaring the function as a friend, then defining the inline function once the definition of the class is complete.

This is the case for h, which does not depend on any template parameter, and for f, which does depend on a template parameter but that parameter has the same type (int) in your example.

Function g has different definitions in the src1.cpp and src2.cpp, so this is a potential ODR violation. This results in the program being ill-formed (no diagnostic required) if the function is ODR-used within both translation units.